testsprite command returns a stable exit code. Agents and CI pipelines branch on the exit code; the JSON error envelope supplies the machine-readable detail. Exit codes and error codes will not change within a major version.
Exit codes
| Code | Meaning |
|---|---|
0 | Success |
1 | Generic failure — non-passed run status, or unhandled server error (INTERNAL) |
2 | Not yet implemented |
3 | Auth error — key missing, unparseable, revoked, or forbidden scope |
4 | Not found — ID doesn’t exist or belongs to another tenant |
5 | Validation error — bad field/enum, payload too large, missing required flag, or bad --output value |
6 | Conflict or precondition — snapshot in flight, run already in flight, idempotency body mismatch, a newer codeVersion was seen, or agent install blocked (target exists and differs, no --force) |
7 | Timeout or unsupported — polling ceiling reached (resume with testsprite test wait <run-id>), or feature not on current backend |
8, 9 | Reserved (unused) |
10 | Unavailable or transport failure — retriable with backoff |
11 | Rate limited — honor the Retry-After header |
12 | Insufficient credits — non-retriable; top up in the dashboard |
130 | SIGINT cancellation (Ctrl-C) |
143 | SIGTERM cancellation |
The
--help and --version flags always exit 0. Flag-parse errors exit 5.Error codes
Every error response carries a machine-readablecode string alongside the HTTP status and CLI exit code.
| Code | HTTP | Exit | When | Retriable |
|---|---|---|---|---|
AUTH_REQUIRED | 401 | 3 | No auth header present | No |
AUTH_INVALID | 401 | 3 | Key unparseable or revoked | No |
AUTH_FORBIDDEN | 403 | 3 | Missing scope or cross-tenant access | No — text mode also prints required: / granted: scopes |
NOT_FOUND | 404 | 4 | ID doesn’t exist or belongs to another tenant | No |
VALIDATION_ERROR | 400 | 5 | Bad field, enum value, or cursor | No |
PAYLOAD_TOO_LARGE | 413 | 5 | Body over the size cap | No |
CONFLICT | 409 | 6 | Snapshot in flight or run already in flight | Yes — once, 1 s delay |
PRECONDITION_FAILED | 412 | 6 | The test changed since you fetched it (newer codeVersion) | No — re-fetch then retry |
IDEMPOTENCY_BODY_MISMATCH | 409 | 6 | Same idempotency key reused with a different body | No |
RATE_LIMITED | 429 | 11 | 60 triggers/min/key exceeded | Yes — honor Retry-After, cap 3 retries |
INSUFFICIENT_CREDITS | 402 | 12 | Credit balance insufficient | No |
UNSUPPORTED | 501 | 7 | Feature not on current backend version | No |
INTERNAL | 500 | 1 | Unhandled server error | Yes — once |
UNAVAILABLE | 503 | 10 | A downstream service is temporarily unavailable | Yes — exponential backoff, cap 4 retries |
Error output
Every command emits the same JSON error envelope when something goes wrong, regardless of--output mode:
message and nextAction as human-readable lines. For AUTH_FORBIDDEN, text mode also prints the required scope list and the granted scope list so you can immediately identify what’s missing.
Test and run status
Test status
The test-level normalized status reflects the outcome of the most recent completed run. The CLI exposes 9 values.| Status | Meaning | Terminal? |
|---|---|---|
| draft | Exists, but no executable code yet | No |
| ready | Has code, never run | No |
| queued | Run accepted; cloud engine not started | No |
| running | Run in flight (pre-exec, exec, or post-exec analysis) | No |
| passed | Latest completed run passed | Yes |
| failed | Latest completed run failed (includes infra crash) | Yes |
| blocked | Run rejected before a real verdict | Yes |
| cancelled | Cancelled before verdict | Yes |
| unknown | Backend cannot derive a status | n/a |
Run status
An individual run has 6 possible statuses. Terminal statuses are the four that produce a final verdict.| Status | Terminal? |
|---|---|
| queued | No |
| running | No |
| passed | Yes |
| failed | Yes |
| blocked | Yes |
| cancelled | Yes |
Step status
Each step in a run is: passed, failed, ornull (not yet executed or not applicable).
Run source
Thesource field on a run identifies which surface triggered it.
| Value | Meaning |
|---|---|
cli | Any CLI-triggered run, including test rerun |
portal | Web Portal |
mcp | MCP Server (IDE integration) |
schedule | Automated schedule |
github_action | GitHub Actions integration |
Retrying safely
Retriable codes — use an idempotency key so retries are deduplicated server-side:- Exit
6(CONFLICT) — retry once after 1 second. ForPRECONDITION_FAILED, re-fetchcodeVersionfirst, then retry. - Exit
10(UNAVAILABLE) — retry with exponential backoff (capped at 4 retries automatically by the CLI). - Exit
11(RATE_LIMITED) — wait for theRetry-Afterduration before retrying (cap 3 retries automatically).
- Exit
4(NOT_FOUND) — verify the ID. - Exit
5(VALIDATION_ERROR,PAYLOAD_TOO_LARGE) — fix the input. - Exit
12(INSUFFICIENT_CREDITS) — top up your balance.
--idempotency-key on write commands when retrying manually so the backend dedupes server-side.
Safe retries
How idempotency keys make manual retries safe
Where to Go Next
Command Reference
Every command and flag in one place
Configuration
Environment variables, profiles, and the JSON output contract
CI/CD Integration
Gate pipelines on exit codes
Running Tests
Triggering runs and handling results