# Errors

The error format, every status code, errors in a stream, retries and debugging.

## Format

```json
{
  "error": {
    "code": 400,
    "message": "invalid chat completion request",
    "metadata": { "fields": { "messages": "messages must be a non-empty array" } }
  }
}
```

- `code` equals the HTTP status.
- `message` is in English. When a provider rejects a request (`4xx`), its own message is passed on without parts that name the provider or link to it; for a provider rate limit (`429`) or failure (`5xx`) the message is the router's.
- `metadata.provider_name` names the region of the provider that failed: `global` or `ru`.
- `metadata.fields` maps each invalid field to its problem, for `400` validation errors.

## Status codes

| Status | When                                                                                                                                                | Retry?                |
| ------ | --------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------- |
| `400`  | Invalid body; unknown model (`model … is not available`); no route for the model and the request (`no route of …`); a provider rejected the request | No: fix the request   |
| `401`  | Invalid, disabled, expired or revoked API key                                                                                                       | No                    |
| `402`  | Not enough PnP, or a key or space budget is reached                                                                                                 | After a top-up        |
| `403`  | The space has no payer, lost access to it, or is deleted                                                                                            | No                    |
| `404`  | `GET /generation`: no such generation in this space                                                                                                 | No                    |
| `409`  | The payer of the space changed during the request                                                                                                   | Yes, at once          |
| `413`  | The body is over 4 MiB                                                                                                                              | No                    |
| `422`  | A provider could not process the request                                                                                                            | No                    |
| `429`  | A router or provider rate limit                                                                                                                     | Yes, with backoff     |
| `502`  | A provider failed before the answer started                                                                                                         | Yes, with backoff     |
| `503`  | The router could not confirm the payer's balance, its limits are unavailable, or it is overloaded                                                   | Yes, with backoff     |
| `504`  | A provider did not answer in time                                                                                                                   | Yes, or use streaming |

## Errors in a stream

After a stream has started, the status is `200` and an error arrives as an event with `error` and `finish_reason: "error"`. See [Streaming](/docs/en/streaming#errors-in-a-stream).

## Retries

- Retry `429`, `502`, `503`, `504` and `409` with exponential backoff and jitter.
- Do not retry `400`, `401`, `402`, `403`, `413`, `422`: the same request fails again.
- There is no idempotency key, and a retry is a new request. An error the provider returned before the answer started is not billed; after a timeout in the middle of an answer, the part generated is billed. Check `billable` of the attempts in `GET /api/v1/generation` when in doubt.
- Better than retrying the same model: give fallback models in `models`, see [Models and routing](/docs/en/models-and-routing#fallback-models).

## Debugging

- Every response has an `X-Request-Id` header. Mention it when you contact support.
- A generation has an id (`id` of the response, `X-Generation-Id` of a stream). `GET /api/v1/generation?id=gen-…` shows its state, tokens, cost and every attempt with its status, see [GET /generation](/docs/en/api/generation).
- The cabinet logs show the same for every call, and the request and answer when content logging is on.
