LLM API error codes: a reference with fixes
An LLM API error is an HTTP status plus a JSON error object carrying type, code, message and request_id. The status tells you who is at fault: 4xx is your request or your key, 5xx is the model provider. This page covers the nine codes that go2llm and the official Anthropic and OpenAI APIs return most often, and each one links to a page that reproduces it and fixes it.
Written 2026-09-12. The same table in machine-readable form lives in the API docs.
Every code in one table
| HTTP | error.code | What to do |
|---|---|---|
| 400 | invalid_request | Check the JSON and the required fields model, messages, max_tokens |
| 400 | unsupported_content_type | Remove image, audio, video and PDF blocks from a text request |
| 400 | model_protocol_mismatch | Take the right endpoint for the model from GET /v1/models |
| 401 | no-key | Send a valid gk_sk_… key in x-api-key or Authorization: Bearer |
| 402 | insufficient_balance | Top up from $1, or lower max_tokens |
| 403 | model / inactive / expired / ip | Check the key's model list, expiry and IP allow-list |
| 404 | model_not_found | Copy the exact public model ID from GET /v1/models |
| 404 | — (on /v1/responses) | Switch clients: go2llm has no Responses API |
| 409 | idempotency_conflict | Do not reuse an Idempotency-Key for a different body |
| 413 | request_too_large | Shrink the body: the limit is 20 MiB |
| 429 | rate_limit | Wait out Retry-After; the default is 20 RPM per key |
| 429 | quota | Raise the key's dollar quota or create a second key |
| 502 | upstream_unavailable | Retry a safe text request with exponential backoff |
| 503 | product_paused / no_eligible_route | Check GET /status and retry later |
A separate category is the errors returned not by go2llm but by the vendors themselves: authentication_error with the text invalid x-api-key from Anthropic, insufficient_quota and your credit balance is too low from OpenAI and Anthropic, unsupported_country_region_territory from OpenAI, and overloaded_error with status 529 from Anthropic. They get their own treatment below, because the literal string is what developers actually paste into a search box.
How to read an error response
go2llm returns one JSON object with four fields. Parse all four: the HTTP status alone is not enough, because one 400 and one 429 each cover several distinct causes with different fixes.
{
"error": {
"type": "insufficient_balance",
"code": "insufficient_balance",
"message": "not enough spendable balance",
"request_id": "gw_4f1c8a2e9b7d40c3a15e6f2b8c9d0e1a"
}
}
error.type is the class of the error, and it is what decides retry-or-not. Only upstream_unavailable, rate_limit and product_paused are safe to retry. Everything else returns the same answer on the second attempt.
error.code is the machine code you branch on. For gateway errors code equals type, but keep them separate anyway: the authorization codes (no-key, inactive, expired, ip, model) come from the key subsystem and distinguish four different reasons hiding under one 403.
error.message is the human-readable explanation — missing or unknown api key, model not allowed for this key, Only text input is supported; rejected image at messages.0.content.1.source. Do not regex the message; the wording changes. Branch on code.
error.request_id is the request identifier, prefixed gw_. It is the one thing worth attaching to a support email at support@go2llm.tech or a message to @go2llm_support. Detailed request logs are kept for 90 days; prompts and completions are not written to product logs, so a request_id reconstructs the route, the usage, the cost and the status — but not the content.
go2llm also sends a Retry-After header in seconds on 429 and 503. For product_paused it is 60 seconds.
A retry strategy that works
A correct retry for an LLM API rests on three rules. First: retry only 429, 502, 503 and network timeouts — 400, 401, 402, 403, 404 and 409 are not cured by repetition. Second: honour Retry-After when the header is present. Third: always add jitter, or ten parallel workers that all saw the same 429 will hit the gateway again in lockstep at exactly 1, 2 and 4 seconds.
import random, time
import httpx
RETRYABLE = {429, 502, 503}
BASE_URL = "https://go2llm.tech/v1/chat/completions"
def call_with_retry(payload, api_key, max_attempts=5, base=1.0, cap=32.0):
with httpx.Client(timeout=120.0) as client:
for attempt in range(max_attempts):
r = client.post(
BASE_URL,
headers={"Authorization": f"Bearer {api_key}"},
json=payload,
)
if r.status_code < 400:
return r.json()
if r.status_code not in RETRYABLE or attempt == max_attempts - 1:
err = r.json().get("error", {})
raise RuntimeError(
f"{r.status_code} {err.get('code')}: {err.get('message')} "
f"[request_id={err.get('request_id')}]"
)
server_hint = r.headers.get("retry-after")
if server_hint and server_hint.isdigit():
delay = float(server_hint)
else:
delay = min(cap, base * (2 ** attempt))
time.sleep(delay * (0.5 + random.random() / 2)) # full-range jitter
Five attempts with a 1-second base and a 32-second cap add up to roughly 23 seconds of waiting in the worst case, which is a sane ceiling for an interactive request. For background jobs raise max_attempts to 8 and cap to 60 seconds.
Two exceptions that tutorials skip. First, a stream cannot be retried after the first valid SSE event: go2llm can swap in a compatible fallback route only before the first byte of the response, and a client-side retry after that produces a duplicate. Second, ambiguous_upstream_result on media requests must not be retried automatically: the provider may have accepted the request, and a repeat charges twice.
What an error costs
A failed request to go2llm does not charge you. The gateway reserves an estimated cost before the call, settles the actual cost after it, and releases the remainder of the reservation; the balance never goes below zero. The real cost of every successful request arrives in usage.cost_usd, including in the final usage block of an SSE stream. Prices for every published model are on the pricing page: claude-sonnet-5 is $0.33 per 1M input tokens against the official $2.00.
Every error code on this site
- \"You exceeded your current quota\" / insufficient_quota: three different limits, one message — OpenAI's insufficient_quota versus go2llm's own 402 insufficient_balance and 429 quota: what each one actually tracks, how to tell them apart with GET /v1/me, and how to fix each.
- 400 invalid_request_error: malformed JSON, missing fields, and go2llm's invalid_request — Why an LLM API returns 400 invalid_request_error or invalid_request, five causes ranked by frequency, the exact go2llm messages, and how to validate a body before sending it.
- 400 stateful_responses_unsupported: why previous_response_id and store fail on /v1/responses — Why go2llm rejects previous_response_id, store, and background on POST /v1/responses with 400 stateful_responses_unsupported or background_unsupported, and how to fix the request.
- 400 unsupported_content_type: why images and PDFs get rejected on text endpoints — Why an LLM API returns 400 unsupported_content_type for images, PDFs, and audio sent to a text endpoint, how to read the rejected field path, and how to fix the request.
- 401 authentication_error and invalid x-api-key: why your key is rejected — The 401 authentication_error / invalid x-api-key error: what it means, what Anthropic and go2llm return, seven causes, and a step-by-step fix with curl and Python.
- 402 insufficient_balance and your credit balance is too low: what it means and how to fix it — Why an LLM API returns 402 insufficient_balance or your credit balance is too low, how reserve-and-settle billing works, and how to stop a batch job dying halfway.
- 403 unsupported_country_region_territory and region not supported: causes and fixes — Why Claude and OpenAI return 403 unsupported_country_region_territory, why a VPN usually does not fix it, and what the four distinct 403 codes on a gateway mean.
- 404 model_not_found: why the model isn't found and how to fix the ID — Why an LLM API returns 404 model_not_found, six causes from dated Anthropic IDs to the wrong endpoint, and how to check the exact ID with GET /v1/models.
- 404 on /v1/responses in Codex CLI: what wire_api actually means — Why Codex CLI returns 404 on a custom provider's /v1/responses, why wire_api = \"chat\" is rejected outright, and the live fix now that go2llm publishes the endpoint (verified 2026-09-14).
- 409 idempotency_conflict: an Idempotency-Key reused for a different request — Why go2llm returns 409 idempotency_conflict or request_in_progress on POST /v1/images/generations, the Idempotency-Key format, and how to fix it step by step.
- 413 request_too_large: your request body is over 20 MiB — Why an LLM API returns 413 request_too_large, how go2llm's 20 MiB body limit differs from the direct Anthropic API's 32 MB, and how to shrink a request without losing data.
- 429 rate_limit_error: what actually triggers it and how to retry properly — Why an LLM API returns 429 rate_limit_error, the difference between a rate limit and a quota, how to read Retry-After, and a retry loop with jitter that does not make things worse.
- 500 internal server error on the OpenAI API: what reaches you through go2llm — What OpenAI's own 500 server_error means, why it is the vendor's fault and not yours, and which of the two envelopes go2llm hands back — a relayed 500 or a 502 upstream_unavailable.
- 502 upstream_unavailable and 503: what's actually safe to retry — Why an LLM API returns 502 upstream_unavailable or 503 (product_paused, no_eligible_route), when retrying helps, and a Python backoff-with-jitter loop that won't double-charge you.
- 504 gateway timeout on an LLM API: what actually timed out, and why go2llm answers 502 instead — 504 Gateway Timeout usually comes from a proxy in front of the real API, not the provider itself. What go2llm's own 180- and 60-second upstream deadlines do, and how to stop hitting either.
- 529 overloaded_error on Anthropic: what it means and why go2llm rarely shows it — What Anthropic's 529 overloaded_error means, how Claude Code and the official SDKs handle it, and why go2llm returns 502 or 503 instead, or no error at all.
- context_length_exceeded and maximum context length exceeded: what to do — Why context_length_exceeded and maximum context length exceeded happen on Claude- and OpenAI-shaped APIs, who actually returns it, and how to check your token count before you hit the wall.
FAQ
What is the difference between error.type and error.code? type describes the class of error and drives the retry decision; code is the precise machine code you branch on. For gateway errors the two match. For authorization errors code is more specific and takes the values no-key, inactive, expired, ip, model, quota.
Which codes are safe to retry automatically? 429, 502, 503 and network timeouts. Retrying 400, 401, 402, 403, 404 or 409 is pointless: go2llm returns the same response until the request, the key or the balance changes.
Where do I find request_id if the body will not parse? It is in the response body at error.request_id and starts with gw_. If the body is empty and the status is 502 or 503, the connection dropped before the gateway formed a response; attach the request time to the second, plus the model, to your support message.
Why is the error message in English? error.message is English so that the text matches the official Anthropic and OpenAI APIs and does not break existing handlers during a migration.
Get a key and make your first request in 3 minutes → go2llm.tech. Registration credits $1 to your balance, which covers a first request without topping up. Full API reference: go2llm.tech/docs.