# Errors

> The error envelopes, status codes and error codes the API returns, and how to fix each.

Errors from the endpoints that reach a model, and from Key, carry `x-request-id`. Quote it when you contact support. A request that Deference forwarded to a provider appears in [Activity](https://deference.si/docs/dashboard/activity) under that id, including one the provider failed. A request that Deference refused before forwarding it, with a 400, 401, 402, 404, 413, 429 or 503 of its own, does not appear there. `GET /v1/models/{id}` answers an unknown model with a 404 that carries no request id.

## OpenAI envelope

Chat completions, Responses, Embeddings, Images, Models and Key return this shape.

```json
{
  "error": {
    "message": "This account has no credit left. Add credit in the dashboard to continue.",
    "type": "insufficient_credit",
    "code": "insufficient_credit",
    "param": null
  }
}
```

## Anthropic envelope

Messages returns this shape, which Claude Code parses.

```json
{
  "type": "error",
  "error": {
    "type": "billing_error",
    "message": "This account has no credit left. Add credit in the dashboard to continue."
  },
  "request_id": "req_01K7Z4F2XQ"
}
```

## Status and type

| Status   | OpenAI `type`           | Anthropic `type`        |
| -------- | ----------------------- | ----------------------- |
| 400      | `invalid_request_error` | `invalid_request_error` |
| 401      | `authentication_error`  | `authentication_error`  |
| 402      | `insufficient_credit`   | `billing_error`         |
| 403      | `permission_error`      | `permission_error`      |
| 404      | `invalid_request_error` | `not_found_error`       |
| 413      | `invalid_request_error` | `request_too_large`     |
| 429      | `rate_limit_error`      | `rate_limit_error`      |
| 502, 504 | `api_error`             | `api_error`             |
| 503      | `api_error`             | `overloaded_error`      |

## Codes

Codes are in `error.code` in the OpenAI envelope. The Anthropic envelope carries the type only.

| Status | Code                           | Cause                                                                                                                                                                       | Fix                                                                                                             |
| ------ | ------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------- |
| 400    | `invalid_json`                 | The body is not valid JSON                                                                                                                                                  | Send a JSON object                                                                                              |
| 400    | `missing_model`                | The request has no `model`                                                                                                                                                  | Add a model id                                                                                                  |
| 400    | `invalid_parameter`            | Images: `n` is not a whole number from 1 to 10                                                                                                                              | Send a valid `n`                                                                                                |
| 400    | `unsupported_parameter`        | The body sets `models`, `route` or `provider`, a `plugins` entry that adds a fee, X search or audio input, or sends a file to a model without file input and no free parser | Name one model and drop those fields. For files, add the `cloudflare-ai` parser or pick a model with file input |
| 400    | `unsupported_model`            | The model bills per search or per song, such as `perplexity/sonar-deep-research` and the Lyria models                                                                       | Use another model                                                                                               |
| 401    | `missing_api_key`              | No key was sent                                                                                                                                                             | Send `Authorization: Bearer sk-df-...` or `x-api-key`                                                           |
| 401    | `invalid_api_key`              | The key is not recognized                                                                                                                                                   | Copy the key again, or create a new one                                                                         |
| 401    | `api_key_disabled`             | The key is disabled                                                                                                                                                         | Enable it in API keys, or use another key                                                                       |
| 401    | `api_key_expired`              | The key passed its expiry                                                                                                                                                   | Create a new key                                                                                                |
| 402    | `insufficient_credit`          | The account has no available credit, or less than the request's hold. A file, image or video given as a URL is held at the model's whole context window                     | Add credit, lower `max_tokens`, or send fewer URL inputs                                                        |
| 402    | `key_limit_reached`            | The key hit its credit limit, or has less left than the request's hold                                                                                                      | Raise the limit, lower `max_tokens` or use another key                                                          |
| 402    | `free_credit_not_eligible`     | The account has only free credit, and this model or request does not qualify                                                                                                | Use an open-weight text model, set a lower `max_tokens`, or add credit                                          |
| 404    | `model_not_found`              | The model id is not in the catalog                                                                                                                                          | List models and pick a current id                                                                               |
| 413    | `request_too_large`            | The body is over 32 MB, or 64 MB on Images                                                                                                                                  | Send a smaller body                                                                                             |
| 429    | `rate_limited`                 | Too many requests in a minute                                                                                                                                               | Wait for `retry-after` seconds                                                                                  |
| 429    | `too_many_concurrent_requests` | 8 requests are already running on the key                                                                                                                                   | Retry when one finishes                                                                                         |
| 502    | `upstream_error`               | The model provider returned an error                                                                                                                                        | Retry the request                                                                                               |
| 503    | `service_unavailable`          | Inference is temporarily unavailable                                                                                                                                        | Retry shortly                                                                                                   |
| 504    | `upstream_timeout`             | The provider did not answer in time: 15 minutes for a call that is not streamed, 120 seconds for Images. The call may still have run, so the credit held for it is charged  | Retry, or stream the request                                                                                    |

`free_credit_not_eligible` explains itself: its message lists what free credit pays for and suggests `max_tokens`. See [Free credit](https://deference.si/docs/concepts/free-credit).

## Provider errors

Errors that describe your request pass through from the provider: `400`, `403`, `404`, `408`, `413`, `422` and `429`. Anthropic-format bodies are returned unchanged. A provider `401` or `402`, which concerns Deference's own upstream account, returns `503`. Any other provider failure returns `502`. Both carry your request id and never reveal the upstream account.

## Failures after a stream starts

A stream that fails midway still returns HTTP `200`, and the error arrives as an event in the stream. Activity marks that request failed. A failed request is charged only for what the provider reports. See [Streaming events](https://deference.si/docs/api-reference/streaming-events).

## Retry

Retry `429`, `502`, `503` and `504` with backoff, and honor `retry-after` when present. It is a whole number of seconds. Do not retry `400`, `401`, `402`, `404` or `413` until you fix the cause. See [Rate limits](https://deference.si/docs/api-reference/rate-limits).
