You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[Hackathon] fix(setup): a timeout while verifying the key is reported as "API key rejected", exit 3, instead of REQUEST_TIMEOUT exit 7 #611
setup checks a key with GET /me before saving it. When that request times out on the client side, setup says the key was rejected and exits 3, the auth family. The same stall on any other command gives REQUEST_TIMEOUT and exit 7.
I reproduced it against a local mock that accepts the connection and never answers:
$ TESTSPRITE_API_KEY=sk-user-... testsprite --request-timeout 2 --output json setup --from-env --no-agent
API key rejected by http://127.0.0.1:35585: Request timed out after 2s (client-side). Use --request-timeout <seconds> or TESTSPRITE_REQUEST_TIMEOUT_MS to extend the deadline. [...] profile NOT updated
{
"error": {
"code": "CLI_ERROR",
"message": "API key rejected by http://127.0.0.1:35585: Request timed out after 2s (client-side). [...] did you mean to set TESTSPRITE_API_URL?",
"nextAction": "",
"requestId": "local",
"details": {}
}
}
exit=3
$ testsprite --request-timeout 2 --output json project list # same stalled server
{ "error": { "code": "REQUEST_TIMEOUT", ..., "requestId": "cli_0b3c873d-...", "details": { "timeoutMs": 2000 } } }
exit=7
setup saves nothing in this case. A CI job that runs setup --from-env through a proxy that holds connections open, or against a slow API with a short --request-timeout, fails with "API key rejected" and exit 3, and the natural reaction is to rotate a key that works. The error also loses the typed code, the nextAction, and the cli_… request id the user would send to support.
Details / implementation notes
Root cause. The catch around the ping in runConfigure (src/commands/auth.ts) rethrows InterruptError and any ApiError unchanged and wraps everything else in new CLIError("API key rejected by ...", 3). RequestTimeoutError extends CLIError, not ApiError (src/lib/errors.ts), so the catch wraps it. The comment on that branch only expects "a TypeError from a misconfigured fetchImpl", and the existing test asserts toBeInstanceOf(CLIError) without checking the exit code.
Proposed fix. Rethrow RequestTimeoutError unchanged next to the InterruptError rethrow, or rethrow any CLIError that already carries a typed code, and keep the "profile NOT updated" stderr line. This is the same family as #397 (a preflight timeout reported as exit 1). #470 is the sibling about which deadline this ping uses.
Tests that fail before the fix.
setup --from-env against a fetch that never resolves exits 7 with REQUEST_TIMEOUT, keeps the cli_ request id, and writes no credentials.
A 401 from /me still exits 3 with the typed envelope.
Confirmations
I have searched existing issues and this is not a duplicate.
I have provided my Discord identity above for reward coordination.
Activity
Andy00L commentedon Oct 20, 2026
Duplicate of #614, refiled through the hackathon form so it carries the labels.