# Error codes

Three outcomes, carried on the HTTP status and the `Retry-After` header.
This table is generated from the running gateway's code table.

| Code | Status | Outcome | Retry-After |
|---|---|---|---|
| `invalid_request` | 400 | failed | never |
| `model_ambiguous` | 400 | failed | never |
| `native_conflicts_with_preset` | 400 | failed | never |
| `native_invalid` | 400 | failed | never |
| `recursion_depth_exceeded` | 400 | failed | never |
| `resource_required` | 400 | failed | never |
| `unknown_model` | 400 | failed | never |
| `unsupported_parameter` | 400 | failed | never |
| `multiple_credentials` | 401 | failed | never |
| `unauthenticated` | 401 | failed | never |
| `lifetime_budget_exhausted` | 403 | failed | never |
| `model_not_permitted` | 403 | failed | never |
| `native_not_permitted` | 403 | failed | never |
| `resource_not_permitted` | 403 | failed | never |
| `route_not_permitted` | 403 | failed | never |
| `task_alias_not_permitted` | 403 | failed | never |
| `model_not_found` | 404 | failed | never |
| `not_found` | 404 | failed | never |
| `payload_too_large` | 413 | failed | never |
| `daily_budget_exhausted` | 429 | retry_after | always |
| `key_rate_limited` | 429 | retry_after | always |
| `provider_rate_limited` | 429 | retry_after | always |
| `gateway_error` | 500 | failed | never |
| `native_no_fallback` | 502 | failed | never |
| `provider_error` | 502 | failed | never |
| `provider_unavailable` | 503 | retry_after | always |
| `resource_needs_reauth` | 503 | retry_after | always |

Body, OpenAI rendering:

    {"error":{"message":"…","type":"rate_limit_error","code":"daily_budget_exhausted","param":null},
     "x_gateway":{"retryable":true,"retry_after_seconds":43200,"call_id":"call_…"}}

Anthropic rendering (any request carrying an `anthropic-version` header):

    {"type":"error","error":{"type":"rate_limit_error","message":"…","code":"daily_budget_exhausted"},
     "x_gateway":{"retryable":true,"retry_after_seconds":43200,"call_id":"call_…"}}

`x_gateway.retryable` restates the status class in one boolean. Upstream
provider errors pass through with their own status; on same-dialect
calls their body is verbatim, on cross-dialect calls it is wrapped as
`provider_error` with the upstream status kept. Pass-through routes
(`/ext`) return upstream errors verbatim, always.
