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

# Predictable failures.

> The API returns standard HTTP status codes with a JSON error body shaped for the protocol you called — Anthropic-shaped on /v1/messages, OpenAI-shaped on the OpenAI endpoints. Match on the status; read error.message for the human explanation.

## Status codes

| Status | Type                    | Meaning                                                                                                                                                                                                                                                              |
| ------ | ----------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `400`  | `invalid_request_error` | Malformed JSON or bad parameters — fix the request; retrying the same body will fail the same way.                                                                                                                                                                   |
| `401`  | `authentication_error`  | Missing or invalid key. Check the header for the protocol you're calling.                                                                                                                                                                                            |
| `403`  | `permission_error`      | The key is valid but not allowed to do this.                                                                                                                                                                                                                         |
| `404`  | `not_found`             | Unknown route or unknown model id — check the path and the catalog (`GET /v1/models`).                                                                                                                                                                               |
| `413`  | `invalid_request_error` | Request body too large. Trim the payload or split the work.                                                                                                                                                                                                          |
| `422`  | `invalid_request_error` | The request declares a requirement the chosen model cannot guarantee (e.g. a capability the model doesn't have). Switch models or drop the requirement.                                                                                                              |
| `429`  | `rate_limit_error`      | Transient rate limit (requests/min, tokens/min or concurrency). Carries `retry-after` (seconds) — back off and retry.                                                                                                                                                |
| `429`  | `allowance_exhausted`   | Monthly included usage used up. This is a hard cap: every request — new or cached — returns it until the cycle resets, so retrying won't help. The message names your plan and the next tier; `retry-after` is the seconds to reset. Upgrade to lift it immediately. |
| `5xx`  | `api_error`             | The model did not return a response. Please retry — transient by design; a retry with backoff almost always succeeds.                                                                                                                                                |

## Error body shape

Every error returns a JSON body with an `error` object carrying a `type` and a `message`.
On the Anthropic endpoint it is Anthropic-shaped:

```json title="Anthropic-shaped (/v1/messages)" theme={null}
{
  "type": "error",
  "error": {
    "type": "authentication_error",
    "message": "Invalid API key."
  }
}
```

On the OpenAI endpoints it is OpenAI-shaped:

```json title="OpenAI-shaped (/v1/chat/completions, /v1/responses, ...)" theme={null}
{
  "error": {
    "type": "invalid_request_error",
    "message": "Invalid API key."
  }
}
```

## Retries and backoff

The retry recipe every production agent should ship:

* **Retry only what can succeed** — `429` with type `rate_limit_error` and `5xx`. A 429
  with type `allowance_exhausted` won't clear until the month resets (or you upgrade), and
  a `4xx` will fail identically on every attempt; fix the request instead.
* **Honor `retry-after` exactly** — on `429` it is the number of seconds until capacity
  opens. Waiting less just burns attempts.
* **Exponential backoff with jitter** everywhere else — e.g. 1s, 2s, 4s, 8s with ±20%
  jitter, capped around five attempts.
* **Fail loud after the cap** — surface the final `error.message`; it is written to be
  actionable.

```python title="Minimal backoff loop" theme={null}
import random, time

def with_retries(send, max_attempts=5):
    for attempt in range(max_attempts):
        r = send()
        if r.status_code < 400:
            return r
        if r.status_code == 429:
            time.sleep(int(r.headers.get("retry-after", "1")))
        elif r.status_code >= 500:
            time.sleep((2 ** attempt) * (1 + random.uniform(-0.2, 0.2)))
        else:
            break  # other 4xx: not retryable
    raise RuntimeError(r.json()["error"]["message"])
```

<Note>
  The official OpenAI and Anthropic SDKs already do all of this — including honoring
  `retry-after` — with no configuration. Hand-rolled HTTP clients are where retries usually
  go missing.
</Note>

## Streaming failures

If a stream cannot complete, it ends with a protocol-shaped error event rather than
silently returning an empty response — your client always learns the turn failed. Treat a
mid-stream error like a `5xx`: retry the whole request with backoff. See
[Streaming](/guides/streaming).
