API error codes: what each one means

401 through 503, which of them are worth retrying, and how to tell a gateway error from one the upstream produced.

Errors the gateway raises before your request leaves

Credential problems are 401: a missing or unrecognised key, a revoked key, an expired key. The body is a flat {"error": "..."} with the reason as a string — "unauthorized", "api key revoked", "api key expired". None of these clear on retry.

Funding problems split by kind. A key that has burned through its own per-key quota is 402 "api key quota exceeded". An account with no spendable wallet left is 403 with a message naming which balance is empty. Claude ids additionally draw only on the recharge balance and refuse other wallets, returning 402 with code claude_minimum_balance.

A request the catalog does not recognise is 400. The body names the id: "model not allowed: <id>". Where an id has been retired in favour of a dedicated lane the message names the replacement — "model not allowed: claude-haiku-4-5. Use stable-claude-haiku-4-5 instead." — because the replacement is priced differently and switching to it has to be your call, not a silent substitution. An empty model field is 400 "model is required".

Print the status and the request id, which is what support needs to find the row.
curl -sS -o /tmp/body.json -w '%{http_code}\n' \
  -D /tmp/headers.txt \
  https://token-share.app/v1/messages \
  -H "x-api-key: $TOKEN_SHARE_KEY" \
  -H "anthropic-version: 2023-06-01" \
  -H "content-type: application/json" \
  -d '{
    "model": "claude-sonnet-5",
    "max_tokens": 64,
    "messages": [{"role": "user", "content": "ping"}]
  }'

grep -i '^x-token-share-request-id' /tmp/headers.txt
cat /tmp/body.json

Capacity and availability: 429 and 503

Two models — claude-sonnet-5 and gpt-5.6-luna — carry a per-model concurrency cap. Exceeding it returns 429 with code model_capacity_exceeded and a Retry-After: 1 header, or code model_queue_timeout when the request waited in the lane's queue and the wait ran out. Both clear on their own; back off and retry.

On a stable-* id, 429 arrives as stable_channel_rate_limited or stable_channel_busy, and 503 as stable_channel_unavailable. A dedicated lane does not fall back to the shared pool, so a failure there is returned as a failure rather than absorbed — that is the trade-off the lane is built around.

A 503 with code no_cluster_capacity means no machine could serve that provider at that moment. A 503 "key lookup temporarily unavailable, please retry" is different in kind: the key store could not be reached, so the gateway declined to guess rather than reject a valid key. Both are worth retrying.

When 502 means the upstream, not you

The gateway returns 502 when every provider it tried failed. On /v1/messages the body is Anthropic-shaped — {"type":"error","error":{"type":"api_error","code":"all_providers_failed",...}} — and on the OpenAI-shaped routes it is {"error":{"type":"server_error","code":"all_providers_failed",...}}. Both carry request_id at the top level.

Two narrower 502s exist. "upstream returned an empty body" means a provider promised a body and delivered nothing, which the proxy catches before your client sees an unparseable success. And a provider that answers 200 with an error envelope inside has its status corrected to 502 while its own body is forwarded verbatim, so the provider's own explanation reaches you.

Statuses the gateway does not synthesize are relayed with the provider's own body and status. If you get a 400 that is not one of the shapes above, it came from the model provider and describes your payload — a malformed tool schema, an unsupported parameter, a max_tokens above the model's ceiling.

Common questions

Which errors are safe to retry automatically?
429 in all its forms, and 503 in all its forms — those describe a moment, not your request. 502 all_providers_failed is worth one or two retries with backoff. Do not auto-retry 400, 401, 402 or 403: the same request produces the same answer until you change the key, the balance or the payload.
The error body shape is not what my SDK expects. Why?
Errors raised before routing — auth, allowlist, balance, admission — use the gateway's own shape rather than a provider envelope, so a strict SDK error parser may not recognise them. Read the HTTP status first and treat the body as diagnostic text. Errors produced after routing, including all_providers_failed and every stable-lane failure, are shaped to match the route you called.
How do I report an error so someone can look it up?
Quote x-token-share-request-id from the response headers. It is generated per request, exposed via CORS, and is the key the request is recorded under. The 400 policy_violation body also carries request_id inside the error object for the same purpose.