Error code reference
When a call to the gateway returns 4xx / 5xx, come to this page first to locate the meaning and handling action by status code; the error-body formats (OpenAI / Anthropic / Google styles) and the specific sources of 429, 503, and 502 are also here. To trace from symptoms see Troubleshoot from symptoms.
Status codes
| Status code | error_type | Meaning | What to do |
|---|---|---|---|
| 400 | bad_request / unsupported_feature | Request JSON parse failed; the requested feature/protocol pair is unsupported; or request-body semantic validation failed (e.g. duplicate tool_use ids in the Anthropic request history, see below) | Check the request-body JSON and fields; see Protocol interop matrix for supported protocol pairs; dedupe duplicate tool_use ids |
| 401 | authentication_error | Access key invalid/disabled, and no anonymous fallback | Verify Authorization/x-api-key carries a gateway access key that is enabled |
| 403 | model_access_denied / ip_banned | The key group doesn't authorize that model; or the IP is banned | Check the key's group model / load-balancer list; if IP-banned, wait for the ban timeout |
| 404 | model_not_found | Model doesn't exist (or accessed by primary name after hide_name) | Verify the model name; a hide_name model can only be accessed by alias |
| 413 | payload_too_large | Request body exceeds max_request_size_mb | Compress the body, or raise max_request_size_mb |
| 429 | rate_limit_error / service_unavailable / handler_queue_full / connection_budget_exceeded | Rate-limited (per-key / per-IP / upstream), concurrency full, or overload admission rejection (queue depth / connection budget exceeded) | Distinguish by Sources of 429 below; admission rejections all carry Retry-After, back off and retry per it |
| 500 | internal_error / stream_error | Internal error, stream error, config error | Check the gateway runtime log; check config |
| 502 | bad_gateway / upstream_not_found / lb_degraded | Upstream failure, upstream not found, load-balancer degradation, translation error, connection error | Check the upstream base_url / API key / connectivity (see Sources of 502) |
| 503 | service_unavailable / overloaded_error / upstream_saturated | No available node, stream concurrency cap, global concurrency cap, or all candidate upstreams saturated | See Sources of 503; upstream_saturated carries Retry-After |
| 504 | timeout / outbound_deadline_exceeded | Request timed out, or the outbound attempt-chain total budget was exhausted | Check whether the upstream is too slow or the timeout config too short; retry if needed |
About "unsupported": unsupported endpoints/features/protocol pairs return 400 (
unsupported_feature); a nonexistent model returns 404. The gateway does not return 501.
About tool_use id uniqueness: the Anthropic Messages contract requires every
tool_useblock'sidin the history to be globally unique. The gateway validates requests to/v1/messagesthe same way — a history with duplicatetool_useids returns 400, and the Anthropic client receivesinvalid_request_errorwith a message liketool_use ids must be unique: duplicate id "…", consistent with calling Anthropic's official API directly. In the response direction, the gateway synthesizes a globally uniquetoolu_id for eachtool_useblock; the client echoes it back as-is, no need to care about the upstream-assigned original id.
Error response body formats
The error-body format follows the client protocol, independent of the upstream:
OpenAI style (default)
Applies to /v1/chat/completions, /v1/responses, /v1/images/*, /v1/embeddings, /v1/audio/*, /v1/rerank, /v2/rerank, /v3/*, /v1/services/*.
{
"error": {
"message": "...",
"type": "<error_type>"
}
}The code / param fields are omitted when null.
Anthropic style
Applies to /v1/messages, /v1/messages/count_tokens.
{
"type": "error",
"error": {
"type": "<anthropic_type>",
"message": "..."
},
"request_id": "..."
}type mapping:
| HTTP | anthropic type |
|---|---|
| 400 | invalid_request_error |
| 401 | authentication_error |
| 402 | billing_error |
| 403 | permission_error |
| 404 | not_found_error |
| 413 | request_too_large |
| 429 | rate_limit_error |
| 500 | api_error |
| 504 | timeout_error |
Unlisted status codes (e.g. 502 / 503) fall back to
api_error.
Google style
Applies to /v1beta/models/*, /v1/models/*.
{
"error": {
"code": 429,
"message": "...",
"status": "<grpc_status>"
}
}status mapping:
| HTTP | grpc status |
|---|---|
| 400 | INVALID_ARGUMENT |
| 401 | UNAUTHENTICATED |
| 403 | PERMISSION_DENIED |
| 404 | NOT_FOUND |
| 413 / 429 | RESOURCE_EXHAUSTED |
| 500 | INTERNAL |
| 503 | UNAVAILABLE |
| 504 | DEADLINE_EXCEEDED |
Unlisted status codes (e.g. 402 / 502) fall back to
INTERNAL.
Sources of 429 (different body formats; parsing must be compatible)
| Source | Response body | Retry-After header |
|---|---|---|
| Per-access-key rate limit | Plain text: Rate limit exceeded (N requests per Ns). Retry after Ns | none |
| Per-IP rate limit | JSON: {"error":{"message":"Rate limit exceeded for IP (N/min)","type":"rate_limit_error"}} | none |
| Upstream rate limit | JSON (OpenAI/Anthropic/Google style, per client protocol) | yes: Retry-After: <secs>, plus z-rate-limited: <upstream>:<dimension> |
Overload admission rejection (queue depth exceeded handler_queue_full / data-plane connection budget exceeded connection_budget_exceeded) | JSON (OpenAI/Anthropic/Google style, per client protocol) | yes: Retry-After: <secs> |
When parsing 429, callers must be able to parse both JSON and plain text (per-key rate limiting is plain text).
Overload admission rejection is transient: the gateway itself is healthy, just too many in-flight requests. Back off per
Retry-Afterand retry to recover; persistent occurrence means insufficient capacity, see Environment variable reference → Memory admission and spill and Listening and request limits.
Sources of 503
- Streaming concurrency cap reached (
streaming.max_concurrent_streams, default 200) → 503. - Global concurrency cap reached (
server.max_global_concurrency, default 1000; set0to disable) → 503overloaded_error. - No available upstream node (all excluded) → 503.
- All candidate upstreams saturated (
upstream_saturated) → 503 +Retry-After. When an upstream's hung (beyond threshold, still no first response) in-flight requests reach its bad-link budget, that upstream is excluded from candidates; when all candidates are excluded, it fast-fails instead of queuing and dragging down healthy traffic. This is real-time in-flight counting: a hung request's slot is released the moment it finishes, and the upstream is usable again as soon as it recovers. In a load-balancing scenario, it first fails over across nodes; only when nodes are exhausted does it return to the client.
The first two concurrency caps are not fixed values; they are TOML config fields (not exposed as environment variables by the official image), see Configuration reference → Config-file-only fields.
No credentials and no anonymous fallback returns 401 (see the table above), not 503.
Sources of 502
- Upstream returned an error, connection error, or translation error.
- Load-balancer degradation (all nodes failed).
- A statically-bound single upstream failed (no cross-node failover).
With load balancing configured and
retry_on_different_node=true, a single-node failure auto-fails-over and callers usually don't see 502; persistent 502 means all nodes are unavailable.
FAQ
Q: The gateway returned 501? It doesn't return 501. Unsupported endpoints/features/protocol pairs return 400 (unsupported_feature); a nonexistent model returns 404.
Q: The 429 response body format isn't fixed? Correct: per-key rate limiting returns plain text, per-IP and upstream rate limiting return JSON. When parsing 429, be compatible with both plain-text and JSON bodies.
Q: 502 won't stop? All nodes are unavailable. With load balancing and retry_on_different_node=true, a single-node failure auto-fails-over and callers usually don't see 502. Persistent 502 means the upstream is genuinely fully down; check the upstream config and connectivity.
Q: Is 503 rate limiting or overload? Four possibilities: streaming concurrency cap reached, global concurrency cap reached, no available upstream node, all candidate upstreams saturated. Distinguish by the response body's error.type (rate_limit_error / service_unavailable / overloaded_error / upstream_saturated). No credentials returns 401, not in this list.
Next: Endpoints · auth · protocol interop for the full endpoint list; Client integration and gateway differences for SDK connection and retry advice; Protocol interop matrix for protocol-pair support.
