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

# Errors & Retries

> How Codex reports GraphQL and HTTP errors, which ones are safe to retry, and how long to back off before trying a failed request again.

## How Errors Arrive

Codex is a GraphQL API, so most errors come back in the `errors` array of an otherwise normal response — **HTTP 200 with an `errors` key**, not an HTTP error status. Authentication, payment (402), malformed queries (400), rate limiting and infrastructure failures (502, 503, 504, and an HTML 403 from the edge firewall) fail at the HTTP layer instead; see the table below.

```json theme={null}
{
  "errors": [
    {
      "message": "The requested resources are over capacity. Retry in about 30 seconds — retrying sooner will be throttled.",
      "extensions": {
        "code": "OVER_CAPACITY",
        "retryAfterSeconds": 30
      }
    }
  ]
}
```

> [!WARNING]
>
> If your error handling only inspects HTTP status codes, it will treat these as successful responses. Always check whether the body contains an `errors` array.

## Which Errors to Retry

There is one field to watch: **if an error carries `extensions.retryAfterSeconds`, wait that many seconds before retrying that request.** On rate-limited responses the same value is also sent as the standard `Retry-After` header, so most HTTP client libraries will honor it without any code from you.

| Code | HTTP status | Meaning | Retry |
| - | - | - | - |
| `TOO_MANY_REQUESTS` | 429 | You exceeded your plan's rate limit | After `retryAfterSeconds`, or your own backoff if absent |
| `OVER_CAPACITY` | 200 | We're briefly over capacity and scaling up | After `retryAfterSeconds` |
| `UNAUTHENTICATED` | 401 | Unknown or invalid API key | No, fix the API key |
| (none) | 402 | No `Authorization` header: the request is treated as a pay-per-query [MPP](https://docs.codex.io/agents/mpp.md) call and returns `application/problem+json` | No, send your API key |
| `FORBIDDEN` | 403 | Your key is valid but the account or key is not allowed to make this request — see [Forbidden (403)](#forbidden-403) | No — fix the account state first |
| (none, HTML page) | 403 `Request blocked` | The edge firewall blocked the client IP before the request reached the API (unlike the JSON `FORBIDDEN` 403) | Back off; send the CloudFront request ID and your egress IP to support |
| `ROUTER_UNAVAILABLE` | 503 | Brief server-side outage | Yes, after `Retry-After` (2 seconds) |
| (none) | 502, 504 | The load balancer could not reach the API; the response has no GraphQL body | Yes, with backoff; include the request ID if it repeats |
| `NOT_FOUND` | 200 | What you asked for isn't indexed, such as `tokenWalletStats` for a token we don't track. Unlike other errors, it is billed, because the lookup ran | No, see [Request errors](#request-errors) |
| `INVALID_ARGUMENT` | 200 | An argument is malformed or unsupported: an unknown `networkId`, a malformed address or ID | No, fix the argument |
| `BAD_USER_INPUT` | 200, or 400 for a variable | An argument failed validation | No, fix the input |
| `NOT_AUTHORIZED` | 200 | Your plan doesn't include this field: `Not authorized: please upgrade your plan` | No, upgrade your plan |
| `GRAPHQL_VALIDATION_FAILED` | 400 | The query doesn't match the schema, such as a field that doesn't exist | No, fix the query |
| Everything else | 200 | Unexpected failure on our side | Not automatically — see below |

### Rate limited

A `TOO_MANY_REQUESTS` error means you exceeded your plan's per-second rate limit. When we can tell you exactly when the limit lifts, we do, via `retryAfterSeconds` and the `Retry-After` header.

A 429 **without** `retryAfterSeconds` means your request budget is momentarily empty rather than your account being throttled — capacity typically returns within a second. Back off on your own schedule and retry; don't retry immediately in a tight loop.

See [Rate Limits & Connection Limits](https://docs.codex.io/concepts/rate-limits.md) for the limits themselves.

### Over capacity

An `OVER_CAPACITY` error means the data your query needs is temporarily under more load than it can serve, and we're scaling up. It is not caused by anything wrong with your request — the same query will succeed once you retry.

These arrive as HTTP 200 with the error in the body. Retry after `retryAfterSeconds` (currently 30). Retrying sooner is likely to be throttled and slows the recovery for everyone.

### Request errors

`NOT_FOUND`, `INVALID_ARGUMENT`, `BAD_USER_INPUT`, `NOT_AUTHORIZED` and `GRAPHQL_VALIDATION_FAILED` mean the request can't succeed as written, so retrying won't help. Branch on `extensions.code` rather than the message text: messages are written for people and can change.

One exception has no code. An input value written inline in the query that doesn't match its type, such as a missing required field, returns HTTP 200 with only a message. Pass inputs as variables and the same mistake returns 400 `BAD_USER_INPUT`.

### Forbidden (403)

A `FORBIDDEN` error means the API key was recognized but the request is not allowed right now. The message says why:

| Message | Meaning | What to do |
| - | - | - |
| `Your account has exceeded its usage limit for this billing period, please upgrade your plan` | The account has used its whole allowance for the period and is paused until the period rolls over. | Upgrade your plan, or wait for the next period. |
| `Your API key is not activated.` | The key has been deactivated. | Reactivate it or create a new one in the [dashboard](https://dashboard.codex.io/dashboard?utm_source=codex\&utm_medium=docs\&utm_campaign=concepts-errors). |
| `You've exceeded the maximum number of connections, please upgrade your plan` | The key has reached its WebSocket connection limit. | Close connections you no longer need, or upgrade. See [Rate Limits & Connection Limits](https://docs.codex.io/concepts/rate-limits.md#websocket-connection-limits). |
| `Websockets are not enabled for your account, please upgrade your plan` | Your plan does not include subscriptions, or WebSockets are not enabled on this API key. | Upgrade, or contact support if your plan includes them. |
| `Your account has violated terms of service, please contact support` | The account has been suspended. | [Contact support](mailto:support@codex.io). |

Over WebSocket, the same conditions close the connection with code `4403` and the message as the close reason. An account that becomes paused while a subscription is running is disconnected within about a minute with the reason `Forbidden`.

On compute-unit plans (see [Compute Units](https://docs.codex.io/concepts/compute-units.md)), two more 403 messages can appear:

| Message | Meaning | What to do |
| - | - | - |
| `Your account has an unpaid invoice, please update your payment method` | An invoice could not be collected, or a charge for overage during the billing period failed or was not approved, and every key on the account is paused. | Pay the invoice from the billing portal (**Pay invoice** on the billing page). Access is restored by the payment; a new billing period does not lift the pause. |
| `This API key has reached its configured compute-unit limit.` | This key has its own custom compute-unit limit and has used all of it. Other keys on the account are unaffected. | Raise or remove the key's limit in the dashboard, or wait for the period to roll over. |

With [auto-scale](https://docs.codex.io/concepts/compute-units.md#auto-scale) off, using the whole allowance pauses every key on the account and returns `Your account has exceeded its usage limit for this billing period, please upgrade your plan` until the period rolls over. Turn auto-scale on to keep requests working past the allowance.

### Everything else

Unexpected errors return a generic message with an error code:

```json theme={null}
{
  "errors": [
    {
      "message": "Something went wrong. Error Code: 1a2b3c4d5e6f7890"
    }
  ]
}
```

Don't retry these automatically — the same request will usually fail the same way. Include that error code when you [contact support](mailto:support@codex.io) or ask on [Discord](https://discord.com/invite/9ZB7zcWuBY); it lets us find the exact failure in our logs.

## Retry Strategy

> [!NOTE]
>
> Fixed retry intervals are the most common cause of prolonged rate limiting. If your interval is shorter than the penalty window, every retry lands inside it and extends the problem.

A retry policy that works well against Codex:

1. **Honor `retryAfterSeconds` whenever it's present.** It's computed from the actual condition — it isn't a guess, and it overrides whatever interval you'd otherwise use.
2. **Otherwise use exponential backoff with jitter.** Jitter matters if you run multiple workers: without it they synchronize and retry in a thundering herd.
3. **Cap your retries.** Three to five attempts is plenty; past that the condition needs attention rather than another request.
4. **Don't retry non-retriable errors.** Auth failures and malformed queries will fail identically every time.

If you're hitting rate limits often enough that retry behavior matters, [Optimization](https://docs.codex.io/concepts/optimization.md) covers how to reduce request volume — usually the better fix.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.