Skip to content

Errors

Every error — validation, billing, upstream — uses one envelope the OpenAI SDKs already parse. The same broken request always gets the same error, so retry logic can trust what it reads.

The envelope

every error, every endpoint
{
  "error": {
    "message": "max_tokens (32768) exceeds the limit for your organization (16384).",
    "type": "invalid_request_error",
    "param": "max_tokens",
    "code": "max_tokens_exceeds_cap",
    "metadata": {}
  }
}
  • type — stable taxonomy for branching (matches the table below).
  • code — the precise machine-readable case.
  • param — the offending field, when one exists.
  • metadata — extra machine data on some errors, e.g. the available balance on a 402.

All error codes

CodeHTTPTypeMeaning
context_length_exceeded400invalid_request_errorThe input plus max_tokens exceeds the model context window. The message carries the estimated total and the limit. Shorten the conversation or lower max_tokens; rejected requests are not billed.
image_url_not_supported400invalid_request_errorImages must be inlined as a base64 data: URI. Remote http(s) image links are not fetched.
invalid_json400invalid_request_errorThe body is not valid JSON. Look for a trailing comma or a truncated payload.
invalid_request400invalid_request_errorThe model rejected the body as invalid for this model.
json_mode_no_stream400invalid_request_errorA JSON response format cannot be combined with streaming. Ask for JSON without stream.
json_mode_not_supported400invalid_request_errorThis model cannot enforce a JSON response format.
max_tokens_exceeds_cap400invalid_request_errorThe requested output length is above your organization cap. The message states the current cap.
missing_messages400invalid_request_errorNo messages array in the body.
missing_model400invalid_request_errorNo model field in the body. Send an id from GET /v1/models.
n_not_allowed400invalid_request_errorAsking for more than one completion is disabled by default because it multiplies the bill silently. Contact support to enable it.
reasoning_effort_not_supported400invalid_request_errorThis model does not accept that reasoning_effort level; the message lists the ones it does.
tools_not_supported400invalid_request_errorThis model cannot do tool calling. Pick a model that lists tools in its capabilities.
unknown_parameter400invalid_request_errorA top-level field is not part of the API; param names it. Almost always a typo.
vision_not_available400invalid_request_errorThis model cannot read images. Pick a model that lists vision in its capabilities.
invalid_api_key401authentication_errorThe key is unknown. Check you copied it whole, including the sk-gw- prefix.
ip_not_allowed401authentication_errorThe key is valid but the calling IP is outside its allowlist. Update the allowlist on the key.
key_expired401authentication_errorThe key is past its expiry date. Create a new one.
key_revoked401authentication_errorThe key was revoked in the dashboard. Create a new one.
insufficient_credits402insufficient_creditsThe balance does not cover the estimated cost of this request; metadata carries the available amount and the estimate. Top up, then retry.
missing_scope403permission_errorThe key lacks the scope this endpoint needs, for example usage:read.
model_not_allowed403permission_errorThe model exists but is outside the allowed models list of this key.
org_suspended403permission_errorThe organization is suspended. Retrying will not help — contact support.
generation_not_found404not_found_errorNo request with that id belongs to your organization, or it has not settled yet. Retry in a few seconds.
model_not_found404not_found_errorNo such model, or it is disabled. See GET /v1/models for the current list.
route_not_found404not_found_errorThe path does not exist. If you hit /chat/completions without /v1, your base_url is missing "/v1"; a /v1/v1/ path means it has one too many.
request_timeout408timeout_errorThe model did not answer in time, after our internal retries. Retry with backoff.
idempotency_key_in_flight409invalid_request_errorThe same Idempotency-Key is still being processed. Wait for the first attempt to finish.
request_too_large413invalid_request_errorThe body is over the size limit. Trim the context or split the work.
idempotency_key_reused422invalid_request_errorThe same Idempotency-Key was sent with a different body. Use a fresh key per distinct request.
daily_budget_exceeded429rate_limit_errorThe daily spend cap is reached. retry-after counts to midnight UTC, so raise the budget instead of waiting it out.
rpm_exceeded429rate_limit_errorToo many requests this minute. retry-after gives the seconds left in the window; the same code with retry-after 1 means concurrency slots are momentarily full.
tpm_exceeded429rate_limit_errorThe per-minute token budget is spent. retry-after gives the seconds left in the window.
internal_error500api_errorSomething failed on our side. The incident is recorded automatically; retry, and contact support if it persists.
upstream_config_error500api_errorA model mapping on our side is wrong. Our team is alerted automatically.
upstream_error502api_errorThe provider failed after our retries. Retry with backoff.
no_capacity503service_unavailable_errorCapacity is temporarily unavailable. retry-after is 10 seconds and the request was not billed.

Errors inside a stream

After streaming starts, HTTP is already 200 — failures arrive as a final chunk with finish_reason: "error" carrying this same envelope in an error field. Sample and handling code: Streaming.

Retry guidance

  • Retry with backoff: request_timeout, upstream_error, no_capacity, and 429s with retry-after — the OpenAI SDKs already do this.
  • Fix before retrying: every 400/401/403/404/413/422 — the request itself is the problem.
  • Act, don't retry: insufficient_credits (top up) and daily_budget_exceeded (raise the budget or wait for 00:00 UTC).

Catching the 402 in your code

The OpenAI SDKs have no dedicated exception class for 402 — it surfaces as the generic APIStatusError (Python) / APIError (Node), so a handler written only for RateLimitError or AuthenticationError will miss it. Branch on the status or on error.code:

catching 402
# Python
import openai
try:
    resp = client.chat.completions.create(...)
except openai.APIStatusError as e:
    if e.status_code == 402:
        print("Out of credits:", e.body["error"]["message"])  # includes balance + top-up link
    else:
        raise

// Node
try {
  const resp = await client.chat.completions.create({...});
} catch (err) {
  if (err instanceof OpenAI.APIError && err.status === 402) {
    console.error('Out of credits:', err.error?.message);
  } else throw err;
}