Skip to main content

Claude API Error 500: Handle Internal Server Errors and Persistent Failures

A returned Claude API 500 api_error calls for bounded retries and request evidence. If it keeps failing, stop the immediate loop, defer safe work, and send a redacted reproduction to the service owner.

LaoZhang AI TeamPublishedUpdated 11 min read
On this page
Claude API 500 recovery uses actual error evidence and bounded retry decisions

A direct Claude API response with HTTP 500 and error.type: "api_error" means an unexpected internal Anthropic error. Keep the failed request's identifier, check Claude Status, and let a bounded retry policy finish if the work is safe to repeat. If the same request keeps failing, stop the immediate loop: return a temporary-unavailable result, defer a still-valid background job, or contact support with a redacted reproduction. This follows Anthropic's API error guidance.

Before adding your own loop, check whether the SDK or gateway already retries. The Python SDK retries eligible failures twice by default; a second loop can multiply attempts and waiting. The configuration and failure handler below give you a usable SDK-managed policy, followed by the evidence and stopping decisions for persistent errors.

If the error appears in Claude Code, during OAuth login, or only as a banner in an app, use the matching section below first. Those messages do not, by themselves, establish that your application received a direct Messages API 500 api_error.

Confirm the HTTP response before choosing a fix

Start with the HTTP status, response body, and endpoint that answered. For a direct Anthropic 500, preserve error.type, error.message, and any request identifier. For a proxy or gateway, retain its response as well as any upstream details the operator exposes; an HTML error page may have come from that intermediary.

What you actually receivedWhat it means on the direct Claude APINext action
500 api_errorUnexpected internal API failureUse bounded backoff, keep failed-request evidence, and stop or escalate if persistent
529 overloaded_errorTemporary overloadReduce concurrent pressure and follow Claude API 529 handling
429 rate_limit_errorRate limit, usage-tier monthly spend cap, or Claude Code workspace spend limitInspect the applicable limits; a tier spend-cap 429 has no retry-after and persists until access resumes
504 timeout_errorThe request timed out during processingReview request duration and streaming for long requests
400, 401, or 413Invalid request, authentication problem, or oversized request, respectivelyAddress that returned error rather than apply a 500 recovery policy
Connection or client timeout exception without an HTTP responseThe client did not obtain a usable responseInspect the exception, effective endpoint, transport timeout, and network or proxy path

The status definitions and spend-cap exception come from the API reference. A clean 500 api_error does not establish that the key expired, billing ran out, or the prompt was invalid. Changing those settings is not a default repair.

A missing request ID is not proof that the request never reached the API. A gateway can remove headers, and a wrapper can hide fields. Classify the failure using the available HTTP response and exception type. Record unavailable identifiers as unavailable rather than inventing one or relabeling an observed 500 as a connection failure.

Check the status service for the endpoint you use, and note the time. If a relevant incident is active, pausing non-urgent work may be the best recovery action. A green public status page cannot prove your particular model, endpoint, gateway, or request is healthy, so verify recovery using the actual failing path.

Configure Python SDK retries before writing another loop

The documented Python defaults are two automatic retries with short exponential backoff for connection failures, 408, 409, 429, and statuses of 500 or higher. That permits an initial attempt plus two retries for an eligible failure. Configure max_retries on the client or through client.with_options(...) for one call. Source: Python SDK retries.

Choose one place to schedule retries:

Retry ownerConfigurationWhat your caller does
Python SDKKeep the default or explicitly set max_retries=2Make one SDK call, then handle its final success or exception
Your application or job workerSet max_retries=0 on the calls it schedulesOwn the attempt cap, backoff, wait window, and stop/defer result
GatewayConfirm its upstream policy and remove redundant retries where appropriateCount upstream attempts as well as the single request visible locally

For example, three outer calls with two SDK retries each can generate up to nine HTTP attempts: 3 × (1 + 2). This is a calculation for those settings and eligible failures; it is not a measured count or a universal SDK guarantee.

The documented request timeout defaults to 10 minutes, and APITimeoutError is also retried by default. Setting timeout=20.0 changes the request's transport timeout; it does not guarantee a 20-second overall deadline. Retries, server-directed waits, and time spent in the request all affect elapsed time. Source: Python timeouts.

A failure handler with a clear stop result

This adapter accepts an already configured anthropic.Anthropic client, your accessible model ID, and valid Messages input. It makes a non-streaming request and lets the SDK manage up to two retries. The 256 output-token limit and 20.0 timeout are example application settings to adapt to your task.

python
import anthropic


def call_with_sdk_retries(client, model, messages):
    try:
        message = client.with_options(
            max_retries=2,
            timeout=20.0,
        ).messages.create(
            model=model,
            max_tokens=256,
            messages=messages,
        )
    except anthropic.APITimeoutError:
        return {"outcome": "client_timeout"}
    except anthropic.APIConnectionError:
        return {"outcome": "connection_failure"}
    except anthropic.APIStatusError as exc:
        body = exc.body if isinstance(exc.body, dict) else {}
        error = body.get("error")
        error = error if isinstance(error, dict) else {}
        request_id = (
            getattr(exc, "request_id", None)
            or exc.response.headers.get("request-id")
            or body.get("request_id")
        )
        evidence = {
            "status": exc.status_code,
            "error_type": error.get("type"),
            "request_id": request_id,
        }
        if exc.status_code == 500:
            return {
                "outcome": "temporary_unavailable",
                "evidence": evidence,
            }
        return {"outcome": "different_http_error", "evidence": evidence}
    except anthropic.APIError:
        return {"outcome": "sdk_error_without_confirmed_status"}

    return {
        "outcome": "completed",
        "message": message,
        "request_id": getattr(message, "_request_id", None),
    }

Use completed to consume the returned message. For temporary_unavailable, end this immediate request and either inform the user or let your job system defer safe work. Do not automatically call the adapter again in an unbounded loop. Route different_http_error by its actual status; investigate client timeout, connection failure, and other SDK failures separately. Non-SDK exceptions, such as programming errors, propagate to the caller.

Catch APIStatusError before inspecting status_code. The base APIError and connection exceptions do not all provide that field. Similarly, _request_id belongs to a successful response object; failed HTTP requests need the exception's response headers or available error-body identifier. The adapter returns only a few diagnostic fields, so add your timestamp, endpoint, model, and sanitized error message to your incident record separately. It does not capture every internal SDK attempt.

In the Python SDK main source inspected on October 4, 2026, 500 maps to InternalServerError, while 529 maps to a separate OverloadedError. That source snapshot does not establish your installed release's mapping. Catching the documented APIStatusError interface and checking exact status 500 keeps this handler from treating every server error as the same failure. Sources: SDK interface, status mapping.

The adapter's branches were checked offline with simulated SDK exceptions and responses. No live API request or recovery timing was tested.

When your application owns the retry window

If you need explicit scheduling, disable SDK retries for those calls and use exponential backoff with jitter within your application's attempt and wait limits. Honor server-directed waits: when a required wait exceeds the remaining window, stop or defer rather than shorten it and retry early. Respect an explicit instruction not to retry, where your provider and client expose one.

The Python SDK main snapshot inspected on October 4 honors x-should-retry: false before its status policy and parses retry-after-ms or retry-after, including HTTP dates. These details are version-specific; confirm your installed client instead of assuming all releases behave identically. Source: SDK retry implementation.

Do not sleep after the final failed attempt. Recheck the remaining window before scheduling another call, and end with a usable result when it expires. A pre-call time check can stop new attempts; it cannot forcibly end an in-flight synchronous request. A hard end-to-end deadline requires a separate cancellation and transport design, plus a decision about work that might already have been accepted.

Persistent 500: stop retrying, defer work, and isolate the failure

Classify completed replies, 500 failures, other HTTP errors and transport exceptions before recovery

When the configured retry policy finishes with another 500, the next action is a stop or defer decision. More attempts are not an investigation by themselves. Keep the original evidence, then choose the outcome that fits the job:

  • For an expired interactive request, show a temporary-unavailable result and preserve useful input or completed output.
  • For a background job that remains valid, record its job ID and schedule a later attempt with a cap. Check for an existing worker before enqueueing another copy.
  • If an action may already have written to another system, verify that system's state before replaying it.
  • If many requests on the same route fail, pause non-urgent work with a circuit breaker. Reopen gradually after limited recovery checks, using thresholds suited to your workload.

A business job ID correlates the workflow; each API attempt can have its own vendor request ID. Use both where applicable. Do not assume that adding an arbitrary Idempotency-Key header makes the Messages API or all downstream tools deduplicate the entire workflow.

For a persistent error with no relevant incident, prepare a minimal valid reproduction. Retain the failing model, endpoint, client version, and request options that may matter. Replace private text with safe representative content, simplify one feature at a time, and record which change affected the result. Keep required Messages fields and any necessary tool relationships valid; reducing the payload into a 400 does not reproduce the original 500.

If a small request succeeds while the original shape fails, you have narrowed the case without proving why the server failed. Send that comparison with the original failed-request identifiers. If both fail on the same route, stop the experiment within its budget and escalate. These are diagnostic recommendations, not results from live calls performed for this article.

A model or provider fallback can keep suitable work moving, but choose it deliberately: quality, supported features, data handling, and cost may differ. Preserve the original failure first. Success on the fallback establishes a workaround, not that the original path has recovered.

What to send when you contact support

Support packet with available identifiers, timeline, route, redacted reproduction and paused workload

Anthropic recommends including the request ID for persistent API errors. The API's request-id header normally matches request_id in the error body. Preserve whichever your client exposes; retain both if available. Source: request IDs.

Include the following in a private support report:

  • Failure time and timezone, HTTP status, error type, and sanitized error message.
  • Request ID, plus a gateway or provider trace ID if that route supplies one.
  • Endpoint host and path, model, SDK version, runtime, and whether streaming was enabled.
  • Configured retries, observed retry timeline, final result, and the status page or incident checked at that time.
  • A minimal valid redacted request and any controlled comparison that changed the outcome.
  • The affected workload and what you paused, deferred, or routed elsewhere.

Exclude keys, OAuth tokens, cookies, private prompts, and customer data. If the ID is unavailable, send the remaining details and say so. For a gateway or cloud route, its operator may need to trace the request first and distinguish its outward error from the upstream response. Contact the service that owns the failed endpoint; do not invent an Anthropic trace ID for an intermediary's HTML 500.

Claude Code 500, OAuth 500, and “no response from API”

If the terminal says API Error: 500 Internal server error. This is a server-side issue, usually temporary, read the provider or gateway named at the end of the message and check that service's status. Let any current retry finish. If no usable output or action completed, the Claude Code reference recommends waiting about a minute and retrying. If output or tools may have completed, inspect their results and continue the remaining work using the Claude Code 500 and 529 recovery guide.

A green status page does not establish that a session is corrupt or needs a fresh login. If Code's runtime 500 persists without a posted incident, its documented reporting path is /feedback, with an alternative “Report an error” path where that command is unavailable. Source: Code 500 instructions.

An OAuth error with status code 500 during authorization is a login-stage failure. Preserve that stage, timestamp, and exact wording; it does not prove a Messages API call failed. Check the relevant service status and report a persistent sign-in failure. Do not rotate an API key or delete credentials merely because the login service returned 500.

No response from API, a waiting countdown, or a stream that ends before complete data arrives needs its own diagnosis. A waiting banner can describe a still-pending request, and the network or gateway may hold or interrupt responses. Use the exact Code message and current network guidance before changing timeout settings. Increasing a timeout is not a fix for every returned 500.

For a generic Claude.ai or third-party app banner, use the Claude internal server error guide to identify the service and preserve the conversation.

Streaming can fail after HTTP 200

A successful initial status does not establish that an SSE response completed. Anthropic documents errors that occur after HTTP 200, outside normal returned-HTTP-error handling. The non-streaming adapter above therefore does not cover complete streaming recovery. Source: streaming error boundary.

Handle the stream's errors and completion signals, keep usable output, and mark partial results explicitly. Before restarting a tool workflow, reconcile any actions already executed. Blindly appending a second response or replaying all tools can duplicate text or external changes. Your SDK application needs its own recovery design; it does not automatically inherit Claude Code's continuation behavior.

Frequently asked questions

How many times should I retry a Claude API 500?

The Python SDK documents two retries by default for eligible errors, in addition to the first attempt. That is a default, not a universal recommendation for every workload. Choose an attempt policy and acceptable waiting period, account for gateway retries, and stop or defer when that policy finishes. Source: Python SDK.

Does a green Claude Status page mean the problem is in my code?

No. Public component status is context, not proof that your exact request or route works. Preserve the 500 response and check recovery on the failing endpoint and model. Do not infer that the key, prompt, or session needs replacement from a green page.

Is 500 the same as 529 overload?

No. The direct API defines 500 api_error as an unexpected internal error and 529 overloaded_error as temporary overload. Both can warrant bounded retries, but repeated 529 also calls for reducing incoming pressure. Use the API 529 guide for that response. Source: API error definitions.

What if the error has no request ID?

Keep the HTTP status, response body, endpoint, and failure time you do have. Missing identifiers can result from an intermediary or limited client exposure; their absence alone does not prove a connection failure. Ask the route owner for an upstream trace where available.

Should I keep retrying when one specific request always fails?

Stop when its retry policy is exhausted. Prepare a valid redacted reproduction, simplify one feature at a time, and preserve the failing request IDs for support. A smaller successful request narrows the case; it does not establish the root cause or justify silently changing the user's task.

Sources6

External pages this guide links to, in the order they appear. Last updated Oct 5, 2026.

  1. 1.Claude Statusstatus.claude.com
  2. 2.API error guidanceplatform.claude.com/docs/en/api/errors
  3. 3.Source: Python SDK retriesplatform.claude.com/docs/en/api/sdks/python
  4. 4.status mappinggithub.com/anthropics/anthropic-sdk-python/blob/main/src/anthropic/_client.py
  5. 5.Source: SDK retry implementationgithub.com/anthropics/anthropic-sdk-python/blob/main/src/anthropic/_base_client.py
  6. 6.Claude Code referencecode.claude.com/docs/en/errors