Guides
Every error the gateway returns is an OpenAI-compatible envelope with a stable code. The messages are written so an agent can self-correct from the code and message alone.
Every failure on /v1/chat/completions, /v1/responses, and /v1/models returns the same shape, so existing OpenAI error handling keeps working:
{
"error": {
"message": "The requested model alias is not granted to this identity.",
"type": "permission_error",
"code": "model_not_granted",
"param": null
}
}Branch on code, not the message text; the message is human-readable and may change, the code is stable.
| code | HTTP | Meaning | How to recover |
|---|---|---|---|
| model_location_not_supported | 403 | The request location is outside this model maker's supported regions, or could not be verified. | Choose another model or contact support if the location is incorrect. Retrying, changing keys, or adding credits will not resolve this policy refusal. |
| invalid_json | 400 | The request body is not valid JSON. | Fix the request body. |
| invalid_request | 400 | The request is malformed. | Read the message, fix the request, and resend. |
| invalid_parameter | 400 | A field is invalid; param names it. Tool and structured-format descriptions are capped at 65,536 characters (raised from 8,192 in engine 0.7.41; the message names the limit and the offending length). | Correct that field and resend. |
| unsupported_capability | 400 | A whole capability the model route does not expose (a tool, a modality, reasoning) was requested. | Pick a capable model; check supported_params and modalities in /api/models. |
| unsupported_parameter | 400 | A specific request parameter the model route rejects (e.g. temperature on a reasoning-only route, or top_k / frequency_penalty / presence_penalty / top_logprobs where the route does not accept them); param names it. | Remove the field, or choose a model whose Supported parameters include it (shown on the model page). |
| refusal | 400 | The provider refused the request on policy grounds. The message is always "provider refused the request: <phrase>" with a fixed phrase (never provider prose), and the envelope carries one extra field, refusal_reason, naming the category: cyber_policy, cbrn, content_policy, recitation, data_inspection, or unspecified. | Retrying does not help; the same content is refused again. Change the request, or pick a model from another provider. Not a key, credit, or limit problem. |
| previous_response_not_found | 400 | previous_response_id is unknown or expired on this worker. | Resend the full conversation instead of continuing. |
| invalid_key | 401 | The key is missing, malformed, expired, or revoked. | Fix the Authorization header. |
| model_not_granted | 403 | Your organization cannot call this slug — or the name is not a gateway slug at all. Gateway slugs use the DOT form (claude-fable-5.1, claude-haiku-4.5); Anthropic's dashed wire ids (claude-fable-5-1, dated ids) fail here. | Use a slug exactly as returned by GET /v1/models. |
| idempotency_conflict | 409 | The same Idempotency-Key was reused with a different body. | Use a fresh Idempotency-Key. |
| idempotency_replay_unavailable | 409 / 500 | The original keyed result is gone after a restart. | Resend with a new Idempotency-Key. |
| insufficient_quota | 429 | A spend limit, a free-tier allowance, or your credit balance is exhausted; the message prefix says which — see the free-tier and cap messages below. | Add credits, raise the limit, or opt in to credits overflow (platform-funded lane only). |
| unavailable_route | 429 / 503 | Throttled, or no healthy route right now. | Retry with backoff. |
| gateway_overloaded | 429 | The bounded replay window is full. | Retry with backoff. |
| request_cancelled | 499 | The client disconnected before completion. | Reissue the request if you still want the result. |
| provider_internal | 502 | "provider stream failed": the upstream provider accepted the request and then closed the stream (before or during output) without a terminal event. Not a credit or limit problem; the gateway already retried the rung once. | Retry with backoff — provider-side incidents are episodic (OpenAI's Astra backend dropped large-prompt streams in bursts on 2026-09-06). Claude Code retries 10× on its own; if a burst outlasts that, retry later. |
| all_routes_failed | 502 | Every provider in the waterfall failed. | Retry; if you are on BYOK, check your provider key. |
| provider_output_too_large | 502 | Provider output exceeded the gateway response limit. | Lower max output tokens. |
| gateway_draining | 503 | This instance is draining and is not taking new requests. | Retry; the request lands on another instance. |
| deadline_exceeded | 504 | The request ran past the gateway deadline. | Shorten the work or retry. |
| internal_error | 500 | An unexpected failure. | Retry with backoff. |
unsupported_capability and unsupported_parameter are distinct: the first means a whole capability is off the table for this route (it serves no tools, or no reasoning at all), so switch models; the second means the route serves the capability but rejects one field of your request (for example temperature on a reasoning-only route) — drop that field and resend, or pick a model whose Supported parameters include it.
A refusal is the one error that adds a field to the envelope. refusal_reason is a closed vocabulary (cyber_policy, cbrn, content_policy, recitation, data_inspection, unspecified), so branch on it rather than on the message. It is present on every refusal on /v1/chat/completions, /v1/responses, and /v1/messages, and absent from every other error:
{
"error": {
"message": "provider refused the request: cybersecurity policy",
"type": "invalid_request_error",
"code": "refusal",
"param": null,
"refusal_reason": "cyber_policy"
}
}Any unknown /v1 path returns 404 with code=not_found. The gateway serves /v1/models, /v1/chat/completions, /v1/responses, and the Anthropic Messages API at /v1/messages(whose errors use Anthropic's envelope shape with the same codes).
Every insufficient_quota response starts its message with one of these prefixes. Branch on the prefix when you need to know which ceiling you hit; they are stable.
| message prefix | Meaning | How to recover |
|---|---|---|
| free_limit_reached | This model's free-tier allowance is spent — an hourly or daily token window, a recurring dollar cap, or a lifetime cap — and your org's credits overflow is off (it turns on automatically at your first real payment, and can be turned on by hand only once the org has a card on file and the settled $1 verification), so the free lane throttles. The message names the exact limit and its reset when one exists; a lifetime cap never resets. | If the message names a reset you can wait for it; otherwise (or to keep going now) add credits or subscribe — any real payment turns credits overflow on for the org. A verified org (card + settled $1 verification) can also flip it directly (model page → "Past the free limit → Use credits", or POST /api/credits-overflow with the org's key; both answer 402 verification_required — "add a card and complete the $1 verification to unlock credits overflow" — before that). Or use your own provider key (BYOK is never throttled). |
| free_tier_requires_payment | The free tier needs a card on file AND a settled $1 charge; the org has not met that yet. | Add a card and buy any credits once on /credits; the free tier unlocks on the settled charge. |
| promo_byok_only | The free tier is spent and the org's credit balance cannot cover this request's worst case, so only your own provider key (BYOK) can serve it. | Add credits, or connect your own provider key for this model. |
| key_daily_cap | This API key's daily spend cap would be exceeded by the request's worst case (the message shows the cap, today's usage, and the request's worst case). | Raise the cap under the key's limits, use another key, or wait for 00:00 UTC. |
| insufficient_credits | The org's credit balance cannot cover the request's worst case. | Add credits on /credits. |
POST /api/credits-overflowwith the org's gateway key (it only ever enables) — but an unverified org gets 402 verification_required from both: the free allowance is all there is until the card is verified. The switch belongs to the org that owns the key you are calling with — check which org is active in the dashboard before assuming it is on.Claude Code rewrites some gateway responses into its own copy, so the text you see is not always the gateway's. These are the ones that mislead.
| What Claude Code shows | What actually happened | Fix |
|---|---|---|
| Not logged in · Please run /login | Claude Code has no usable key. Either the key changed under a running session (auth is read at startup), or you once answered No to its "Detected a custom API key… do you want to use it?" prompt — that No is remembered in <config dir>/.claude.json under customApiKeyResponses.rejected and the env key is ignored forever after. | Restart the session (claude --resume <session-id> keeps the conversation). If it persists, answer Yes to the prompt, or move the key's entry from rejected to approved in .claude.json. Do not run /login. |
| API Error: 403 The requested model alias is not granted… | The model name is not a gateway slug (Anthropic's dashed id such as claude-fable-5-1) or the key's org lacks the alias. | Use the dot-form slug from GET /v1/models (claude-fable-5.1). |
| 502 provider stream failed · Retrying | The upstream provider closed the stream. Episodic and provider-side; large-context sessions are hit hardest. | Let the retries run; if all 10 fail, resume the session a few minutes later. It is not a credit or limit problem. |
| "gpt-6-astra" isn't described by this version's model catalog… auto-compact keeps this session within 200k tokens | Claude Code assumes a 200k window for any model name it does not know and compacts early. | Set CLAUDE_CODE_MAX_CONTEXT_TOKENS to the catalog window (gpt-6-astra: 1050000; read context_window from GET /api/models/<slug>). The unrecognized_model stderr line is cosmetic. |
| Fable missing from the /model picker | Claude Code 2.1.263 hides Fable rows on API-key auth even when the org is entitled; the model still serves. | Set "model": "claude-fable-5.1" in the session's settings.json, or pass --model claude-fable-5.1. |
/login on a gateway session. It starts an Anthropic OAuth flow whose token then outranks ANTHROPIC_BASE_URL + ANTHROPIC_API_KEY, and your calls stop reaching the gateway. Claude Code also hides the gateway's 401 body (you only see its login prompt) while it prints 403 bodies verbatim — so a key problem looks like a login problem.429 (throttled or overloaded), 502, 503, and 504 with exponential backoff.400, 401, 403, or 409. Fix the request first; the same call fails the same way.insufficient_quota is not transient: it clears when you add credits or raise a limit, not on retry.Idempotency-Key header so an exact retry replays the original result instead of running again.The API reference documents each endpoint, and /llms.txt carries this same error table for agents.