# Errors

> Failed requests return an HTTP status and a JSON error with a stable code.

Source: https://www.lyber.ai/docs/api/errors/ · Markdown: https://www.lyber.ai/docs/md/api/errors.md

```json
{
  "error": {
    "message": "Model capacity is full; retry later",
    "type": "rate_limit_error",
    "code": "rate_limit_error"
  }
}
```

Branch on `code`; the `message` is for people and can change.

## Status codes

| Status | Codes | What to do |
| --- | --- | --- |
| `400` | `invalid_request_error` `unsupported_parameter` `context_length_exceeded` | Fix the request. Unsupported fields are rejected, never ignored. |
| `401` | `authentication_error` `api_key_expired` | Check the key. See [Authentication](https://www.lyber.ai/docs/api/authentication/). |
| `402` | `insufficient_credit` `request_budget_exceeded` `account_spend_limit_exceeded` `key_spend_limit_exceeded` | Add credit, lower `max_tokens`, or raise a limit. See [Spending controls](https://www.lyber.ai/docs/capabilities/spending-controls/). |
| `403` | `access_approval_required` `model_not_allowed` | Wait for approval, or use a model the key allows. |
| `404` | `model_not_found` | Use one of the two offered model IDs. |
| `408` | `request_timeout` | The body took over 15 seconds to upload. Send a smaller request. |
| `413` | `invalid_request_error` | The body is over 16 MiB. |
| `429` | `rate_limit_error` | Wait and retry. See below. |
| `502` | `upstream_error` `request_outcome_unknown` | The model failed. It may have run; check your request history before resending. |
| `503` | `service_unavailable` `inference_stopped` | The model isn't serving. Retry later. |
| `504` | `upstream_timeout` | The request ran past its time limit. It may have run; check before resending. |

## Retrying safely

`429` and `503` come with `Retry-After: 5`. When a `429` also carries `x-lyber-admission: not-admitted`, the model was busy and your request never started: it's always safe to wait and resend.

Lyber never deduplicates or replays requests. After a `502`, `504`, a dropped connection or a stream that ended early, the request may have run and been charged. Look it up in `GET /v1/credits/requests` before you send it again.
