> ## Documentation Index
> Fetch the complete documentation index at: https://docs.testorim.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Errors

> Every status the API-key surface answers with, the machine-readable codes, and which ones are worth retrying.

Every error is JSON with a human-readable `error` string. Some carry more:

```json theme={null}
{
  "error": "Choose a plan and add a card to start your 3 day trial.",
  "code": "onboarding_exhausted",
  "upgradeUrl": "https://app.testorim.com/pricing"
}
```

`error` is written for a person and can change. Branch on the **status** and
on **`code`** when there is one.

## By status

| Status | `code`                     | Meaning                                                                                                                                                                                                                       | Retry?                      |
| ------ | -------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------- |
| `400`  | none                       | The body failed validation (an `issues` array names each problem), a string held a NUL byte, the base URL is a private or internal host, or a saved procedure's secret would be typed on a host that is not the project's own | No. Fix the request         |
| `401`  | none                       | No `Authorization` header, or the key is wrong, revoked, expired, or its owner has left the workspace                                                                                                                         | No                          |
| `402`  | `onboarding_exhausted`     | The account has never subscribed. Choose a plan and add a card                                                                                                                                                                | No, until you pay           |
| `402`  | `locked`                   | Runs are paused: the plan ended, the subscription is unpaid or paused, or a payment has been past due for more than 72 hours                                                                                                  | No, until you pay           |
| `403`  | `read_only_role`           | The key's owner is a `viewer` in its workspace, and this request changes something                                                                                                                                            | No                          |
| `403`  | `api_key_scope`            | API keys cannot make this change. It belongs to the dashboard                                                                                                                                                                 | No                          |
| `404`  | none, or `other_workspace` | Not found in the key's workspace. `other_workspace` adds `orgId` and `orgName` when the key's owner belongs to the workspace that has it                                                                                      | No                          |
| `429`  | none                       | Rate-limited. Carries `Retry-After` and `retryAfter`                                                                                                                                                                          | Yes, after `Retry-After`    |
| `429`  | `plan_quota_exhausted`     | The period's runs, browser minutes or AI execution allowance are used up, or a trial's runs or minutes are                                                                                                                    | Yes, once the period renews |
| `429`  | `concurrency_limit`        | Your plan's concurrent runs are all in use. No run was created                                                                                                                                                                | Yes, when a run finishes    |
| `500`  | none                       | Something failed on our side                                                                                                                                                                                                  | Yes, with backoff           |

Both `402` codes carry an `upgradeUrl` pointing at the pricing page.
Neither `429` quota code carries `Retry-After`, because the wait is not a
fixed number of seconds.

## Runs that are accepted and then do not run

`POST /api/runs/trigger` answers `202` once the run is created. A few things
can still stop it after that, and they are recorded on the run rather than
returned by the trigger:

* **Every test browser is busy.** The run waits in line. If no browser frees
  up within 3 minutes of reaching the front, or 10 minutes in line
  altogether, it ends with `status: "cancelled"` and the reason in
  `reportMarkdown`.
* **The plan's cap was reached by another run in the meantime.** The run ends
  `cancelled` with the reason.
* **Setup failed** before the browser started. The run ends `cancelled` with
  a neutral reason.

A cancelled run has no verdict: `overallStatus` is `null`. Poll
`GET /api/runs/{id}` until `status` is terminal, then read `overallStatus`.

## The `503` code

`service_busy` (`503`) is the service's own capacity, never your quota. The
trigger endpoint does not return it: a triggered run waits in line instead,
as above.

## Retrying safely

* Retry `429` and `500`, with backoff.
* Do not retry `400`, `401`, `402`, `403` or `404`: the same request gets
  the same answer.
* A retried trigger is a second run. The API has no idempotency key, so
  after a trigger that timed out without an answer, check
  `GET /api/projects/{projectId}/runs` before sending it again.


## Related topics

- [JavaScript and TypeScript library](/developers/javascript.md)
- [Python package and pytest](/developers/python.md)
- [API reference](/api-reference/introduction.md)
- [Browser failures](/troubleshooting/browser-failures.md)
- [CLI](/developers/cli.md)
