Skip to main content

Errors

Errors use Anthropic's exact wire format, so the error handling in your existing SDK integration keeps working unchanged.

Error shape

{
  "type": "error",
  "error": {
    "type": "rate_limit_error",
    "message": "Rate limit reached: 120 requests per minute. Retry in 24s."
  }
}

The HTTP status and the error.type always agree. Messages are written to be shown to a developer — they say what went wrong and what to do — so it is safe to surface them in your own logs.

Error types

Type HTTP Cause What to do
authentication_error 401 Missing, malformed, revoked or expired API key. Check the key is being sent and has not been revoked. Not retryable.
permission_error 403 The key or account is not allowed to do this: a model outside your plan, an IP outside the allow-list, or a suspended account. The message says which. Not retryable without a change.
not_found_error 404 Unknown model or endpoint. Call GET /v1/models for the list you can use.
invalid_request_error 400 The body failed validation — a missing field, a bad type, or a parameter the upstream rejected. Fix the request. Not retryable.
request_too_large 413 The body exceeded the size limit. Split the request or reduce attachments.
rate_limit_error 429 Too many requests per minute, or too many concurrent in-flight requests. Back off and retry. Honour Retry-After.
quota_exceeded 429 The monthly token allowance is exhausted, or the hard overage ceiling was reached. Retrying will not help. Upgrade the plan or wait for the next billing period.
residency_unavailable 422 No upstream can serve this request within your data-residency tier. Choose a model available on your tier, or move to a wider tier. Never retry against a different region.
overloaded_error 503 The upstream is saturated, or a credential we depend on is not configured. Retry with exponential jitter.
api_error 500 Something failed on our side or on the upstream. Retry once, then contact support quoting the x-request-id.

Errors during a stream

Once a streamed response has started, the HTTP status is already sent and cannot change. A failure part-way through therefore arrives as an SSE error event, which is what the Anthropic SDKs expect.

event: content_block_delta
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"Once the"}}

event: error
data: {"type":"error","error":{"type":"api_error","message":"The upstream stream failed."}}

If you are parsing the stream yourself, treat an error event as terminal and stop reading.

Retrying safely

import time, random, anthropic

client = anthropic.Anthropic(api_key=KEY, base_url="{BASE_URL_ROOT}")

def call(**kw):
    for attempt in range(5):
        try:
            return client.messages.create(**kw)
        except anthropic.APIStatusError as e:
            kind = (e.body or {}).get("error", {}).get("type")

            # Never retry these: the answer will not change, and for
            # residency_unavailable a retry could only succeed by
            # breaking the guarantee you are paying for.
            if kind in {"authentication_error", "permission_error",
                        "invalid_request_error", "not_found_error",
                        "quota_exceeded", "residency_unavailable"}:
                raise

            wait = min(2 ** attempt + random.random(), 30)
            time.sleep(float(e.response.headers.get("retry-after", wait)))
    raise RuntimeError("exhausted retries")

Reporting a problem

Every response carries an x-request-id. Quote it when contacting support and we can find the request in our logs immediately. It identifies the request without revealing anything about its contents — we do not store prompt or completion bodies.