Most errors when connecting Claude Code to a third-party API are not model problems; they are configuration, authentication, or network problems. A fresh setup returns 401, a changed Base URL produces 404, a task hits 429 halfway through, and a long task hangs until it times out. The order of handling is: read the status code and error type first, then the request-id, and only then consider changing the prompt. This article breaks down 401, 404, 429, context limits, and timeouts, with troubleshooting steps, a log checklist, and sample code. Model and billing details follow model pricing.
Note: Claude, Claude Code, and Anthropic are trademarks of their respective owners. Error types and API behavior can change between versions; this article describes common cases as of October 2026 and defers to the official documentation.
1. Layered first: which layer failed
A request passes through four layers: client, network, gateway, and upstream model. The same 401 can mean a wrong key or a mismatched authentication header; the same 404 can mean an extra /v1 in the path or a nonexistent model name. Identify the layer first so you do not keep changing the wrong configuration.
| Status | Error type | Common cause | Action |
|---|---|---|---|
| 400 | invalid_request_error | Parameters, format, context length, or spending limit | Fix the request or limit, then retry |
| 401 | authentication_error | Key missing, wrong, expired, or header mismatch | Fix credentials; do not retry |
| 402 | billing_error | Billing or payment information problem | Check billing |
| 403 | permission_error | Key lacks model or project permission | Check permissions |
| 404 | not_found_error | Wrong path or model name | Check Base URL and model name |
| 413 | request_too_large | Request body exceeds the endpoint limit | Split the request |
| 429 | rate_limit_error | Rate, concurrency, or spending limit | Back off and retry |
| 500 | api_error | Internal server error | Back off and retry |
| 504 | timeout_error | Processing timeout | Switch to streaming or batch |
| 529 | overloaded_error | Server overloaded | Back off; reduce concurrency |
Keep the request-id response header; the error response body usually contains request_id as well. When asking a provider to investigate, one request ID is worth ten screenshots. Log at least the time, status code, error type, model name, and request ID. Never log full keys or sensitive content.
2. 401 and 403: auth headers and keys
A 401 means authentication failed; it has nothing to do with balance or model capability. Claude Code has two easily confused variables: ANTHROPIC_API_KEY is sent as X-Api-Key, while ANTHROPIC_AUTH_TOKEN is sent as Authorization: Bearer. If the gateway accepts only one and you use the other, you get a consistent 401. Confirm the requirement first and do not export both.
Other common causes: spaces, line breaks, quotes, or full-width characters around the key; a key that was deleted, expired, or belongs to another workspace; a Base URL pointing at the wrong environment; subscription login and API key set at the same time; a corporate network or proxy rewriting authentication headers.
A 403 is usually a permission problem: the key is not enabled for the model, lacks project permission, is blocked by an IP allowlist, or workspace policy disallows it. Do not retry a 403; check model authorization and access policy in the console first.
Quick isolation: call /v1/messages directly with the same key and Base URL. If the direct call succeeds and Claude Code fails, the problem is client configuration. If the direct call also fails, the problem is the key, gateway, or network.
3. 404: Base URL paths and model names
There are two kinds of 404: wrong path, or nonexistent resource. Claude Code uses the Anthropic Messages API and usually expects the Base URL to be the root address, with the client appending /v1/messages. If the Base URL already includes /v1, the actual path may become /v1/v1/messages.
Check in order:
- Confirm the protocol: Claude Code uses Anthropic Messages, not OpenAI Chat Completions.
- Check whether the Base URL has an extra or missing
/v1. Claude Code generally takes the root address; OpenAI-compatible clients generally take an address with/v1. - Check trailing slashes and capitalization to avoid double slashes or truncated paths.
- Copy the current model name from model pricing; gateway aliases may differ from official names.
- Test with a minimal request to rule out proxies and client caches.
If the message is model not found, check the model name and permissions. If it is not_found_error with an obviously wrong path, check the Base URL.
4. 429: rate limits, quotas, and retry storms
A 429 means the request exceeded a rate, concurrency, or spending limit. Common causes: requests per minute or tokens per minute exceeded; multiple services sharing one key; retries without backoff creating a retry storm; reaching an account or workspace spending cap; a sudden traffic spike triggering acceleration limits.
Some 429s triggered by a spending cap do not include retry-after, and waiting will not restore service; you need to adjust the limit or top up. Check retry-after first and wait as instructed. If it is absent, use exponential backoff with random jitter and set a maximum retry count. Do not retry 401, 403, 404, or 400.
Mind the SDK's default retries: the official Anthropic SDK retries connection errors, 429s, and 5xx responses twice. If your application adds another layer, the actual number of requests multiplies. Plan max_retries together with application-level retries.
A 429 and a 529 are different: with a 429, check your own concurrency, keys, and quota first; a 529 means server overload, so back off, reduce concurrency, and check service status.
5. 400 and 413: context limits and oversized requests
A context-limit error usually returns 400 invalid_request_error with prompt is too long in the message. The model is not broken; the combined input and output budget exceeds the context window.
Handling order:
- Quantify the input with
count_tokensbefore sending; do not guess from character counts. - Trim the oldest history, keeping the system prompt, the most recent turns, and a summary.
- Retrieve relevant passages from documents first; do not load the entire corpus.
- Split long documents by chapter, process the sections, and merge the results afterward.
- Compress tool output to the necessary fields.
- Leave room for output.
max_tokensis only an output cap; it does not solve an input overflow.
A 413 request_too_large means the request body is too large, which is different from context length. Inline base64 images are especially prone to this; compress images, use a file upload endpoint, or split the request.
Not every 400 is a context problem. Parameters unsupported by the current model, invalid thinking configuration, and spending-limit triggers can all return 400. Read the type and specific field in the error message.
6. Timeouts and broken streams: streaming, proxies, and SSL
Claude Code's per-request timeout is controlled by API_TIMEOUT_MS, defaulting to 600000 milliseconds, or 10 minutes. On slow networks or behind proxies you can raise it moderately, but do not increase it without bound, or failures will take a long time to surface.
For long tasks, prefer streaming output or a batch endpoint. A non-streaming request expected to exceed 10 minutes may have its idle connection closed, appearing as a hang or timeout. A streaming request receives data continuously and keeps the connection more stable.
Note: a streaming request may return HTTP 200 first and then send an error event inside the SSE stream. A client that only checks the status code will mistake failure for success. Parse error events in the stream and mark partially generated output as incomplete.
Proxy and certificate problems can also appear as timeouts: corporate proxies require HTTPS_PROXY or HTTP_PROXY; enterprise TLS interception requires trusting the corresponding CA certificate, and Node-based clients commonly use NODE_EXTRA_CA_CERTS; DNS, IPv6, firewalls, and MTU can also cause unstable connections. Switching networks or using a phone hotspot is a quick diagnostic. If the gateway's first byte is slow, watch CLAUDE_STREAM_FIRST_BYTE_TIMEOUT_MS.
7. Logs and support checklist
Do not report only "it failed." Collect information with this checklist:
- Time of occurrence, time zone, and duration.
claude --versionand operating system.- Base URL (keep the domain, exclude the full key).
- Model name, whether streaming was used, request duration, and retry count.
- HTTP status code, error type, and full error message.
request-id, which may appear in both headers and body.- Scope: one person, one network, one project, or the whole team.
- Minimal reproduction: one curl command or a minimal repository, plus the result of the same request against the official endpoint.
Be specific about log redaction: keep only the first four and last four characters of a key, and handle prompts and code content according to company policy.
8. Example: decide whether to retry by error type
The example below retries only 429, 5xx, and network timeouts; 401 and 404 fail immediately so configuration problems do not turn into retry storms. The Base URL and model name are read from environment variables.
import os
import random
import time
from anthropic import (
Anthropic,
APIConnectionError,
APIStatusError,
APITimeoutError,
AuthenticationError,
NotFoundError,
RateLimitError,
)
client = Anthropic(
base_url=os.environ["ANTHROPIC_BASE_URL"],
auth_token=os.environ["ANTHROPIC_AUTH_TOKEN"],
)
def ask(prompt: str, retries: int = 4) -> str:
for attempt in range(retries):
try:
resp = client.messages.create(
model=os.environ["ANTHROPIC_MODEL"],
max_tokens=512,
messages=[{"role": "user", "content": prompt}],
)
return resp.content[0].text
except AuthenticationError as exc:
raise SystemExit(f"401: check key and auth header, request-id={exc.request_id}") from exc
except NotFoundError as exc:
raise SystemExit(f"404: check Base URL and model name, request-id={exc.request_id}") from exc
except RateLimitError:
wait = min(2 ** attempt, 20) + random.random()
print(f"429: retrying in {wait:.1f}s")
time.sleep(wait)
except (APITimeoutError, APIConnectionError):
wait = min(2 ** attempt, 10) + random.random()
print(f"Timeout or connection failure: retrying in {wait:.1f}s")
time.sleep(wait)
except APIStatusError as exc:
if exc.status_code >= 500:
wait = min(2 ** attempt, 20) + random.random()
print(f"{exc.status_code}: retrying in {wait:.1f}s")
time.sleep(wait)
continue
raise
raise RuntimeError("Retries exhausted; degrade or alert")
print(ask("Reply with OK only"))
If the gateway uses X-Api-Key instead of Bearer, replace auth_token= with api_key=, or adjust per the client documentation. The example does not set max_retries explicitly, so the SDK still retries by default; configure this consistently in production.
FAQ
Does a 401 always mean the key is wrong?
No. A mismatched authentication header, a Base URL pointing at the wrong environment, or a proxy rewriting headers can all return 401. Test directly with the same key and Base URL first, then check client variables.
I changed the model but still get 404. What now?
Focus on the Base URL path. Claude Code usually takes the root address and appends /v1/messages; an address that already includes /v1 becomes a double /v1. Next, confirm the model name matches the gateway list.
Will a 429 always recover after waiting?
Not always. Rate limits usually recover, but a 429 triggered by a spending cap may lack retry-after; waiting is pointless and you need to adjust the limit or top up. Check the error type and response headers before deciding.
A streaming request returns 200 and then breaks. Is that a success?
No. A streaming response can send an error event over SSE after the 200. The client must parse the event stream and confirm a normal end event; otherwise mark the result as incomplete and retry or alert.
Do more retries make things more reliable?
No. Retries only solve transient errors; too many attempts amplify failures and cost. Set a ceiling, use exponential backoff and random jitter, distinguish retryable from non-retryable errors, and confirm whether operations with side effects already ran before resending.
Next steps
Create a test key at the ZSQH AI Gateway, rehearse each of 401, 404, 429, and timeout once, then connect production monitoring. Model availability and billing follow model pricing.
Related reading:
