Anthropic 529 overloaded_error: What It Means and How to Handle It
Updated July 27, 2026
overloaded_error from the Anthropic API means Anthropic-side capacity is temporarily exhausted. It is not your quota, so requesting a limit increase changes nothing. Retry the same request with exponential backoff plus jitter, and fail over to another model or provider when the retries run out. A 429 rate_limit_error is the opposite case: that is your own organization budget, and the retry-after header says exactly how long to wait.client = Anthropic(max_retries=5) # SDK retries 429, 5xx and 529 with backoffCauses at a glance
| Cause | How to recognize it | Fix |
|---|---|---|
| Anthropic-side capacity exhausted | HTTP 529 with error.type overloaded_error; unrelated to your usage numbers | Retry with exponential backoff and jitter; fail over after a bounded number of attempts |
| Your own organization rate limit | HTTP 429 with error.type rate_limit_error and a retry-after header | Wait the retry-after interval, smooth traffic, then request higher limits if it persists |
| Retry storm amplifying the outage | 529s cluster on a fixed interval and get worse right after a deploy | Use full jitter and cap concurrent in-flight retries so workers stop resynchronising |
| Large uncached prompts held on every call | usage.cache_read_input_tokens is 0 on every response despite a stable prefix | Add cache_control to the stable prefix: big cut in input tokens, cost, and latency |
| Bulk work running on the synchronous API | 529s only during backfills or evals, never on interactive traffic | Move it to the Message Batches API: separate queue, 50% cheaper |
529 versus 429: whose limit did you actually hit?
Anthropic returns HTTP 429 rate_limit_error when your organization exceeds its own requests-per-minute or input/output tokens-per-minute budget, and HTTP 529 overloaded_error when Anthropic itself is temporarily at capacity. The bodies are what distinguish them: read error.type, not just the status code.
That difference decides who can fix it. A 429 is yours to manage: smooth the traffic, or raise the limit. A 529 is not about you at all, so a limit increase is useless; the only correct responses are patient retries and a fallback path. Treating every 529 as a quota problem sends teams chasing a limit increase that would not have helped.
# 429 — your budget
{"type":"error","error":{"type":"rate_limit_error","message":"Number of request tokens has exceeded your per-minute rate limit"}}
# 529 — Anthropic capacity
{"type":"error","error":{"type":"overloaded_error","message":"Overloaded"}}Step 1: classify the error before you retry
Use the SDK exception classes rather than string-matching the message. In the Python SDK a 429 raises RateLimitError and any status at or above 500 (including 529) raises InternalServerError; check status_code or the .type property to separate a plain 500 from an overload.
Catch the most specific class first and let genuinely non-retryable errors (400, 401, 404) propagate immediately instead of being swallowed by a broad handler.
import anthropic
client = anthropic.Anthropic(max_retries=0) # handle retries explicitly
try:
msg = client.messages.create(
model="claude-sonnet-4-5", max_tokens=1024, messages=messages
)
except anthropic.RateLimitError as e: # 429 — your own limit
wait = float(e.response.headers.get("retry-after", "60"))
except anthropic.InternalServerError as e: # 5xx, including 529
overloaded = e.status_code == 529 or e.type == "overloaded_error"
except anthropic.APIConnectionError:
pass # never reached the API at allStep 2: retry with exponential backoff and full jitter
The Anthropic SDKs already retry connection errors, 408, 409, 429, and 5xx (529 included) with exponential backoff; max_retries defaults to 2. Raising it to 4 or 5 absorbs most transient overloads with no other change.
When you write the loop yourself, use full jitter: sleep a random duration in the window rather than the full backoff interval. Fixed backoff makes every throttled worker retry at the same instant, which recreates the overload at each step. Bound total attempts as well: an unbounded retry against a saturated service is a denial-of-service you inflict on yourself.
import random, time
import anthropic
def with_backoff(fn, attempts=6, base=1.0, cap=60.0):
for i in range(attempts):
try:
return fn()
except (anthropic.RateLimitError, anthropic.InternalServerError) as e:
if i == attempts - 1:
raise
# full jitter: sleep anywhere in [0, min(cap, base * 2**i)]
time.sleep(random.uniform(0, min(cap, base * (2 ** i))))
msg = with_backoff(lambda: client.messages.create(
model="claude-sonnet-4-5", max_tokens=1024, messages=messages
))Step 3: cut input tokens with prompt caching
Prompt caching stores a stable prefix (a long system prompt, tool definitions, a retrieved document) so later requests reuse it instead of reprocessing it. Cache reads are billed at roughly a tenth of the base input rate, and writes at about 1.25x, so the break-even is around two requests on the five-minute TTL. Smaller requests also finish faster, which reduces exposure to capacity blips.
Caching is a prefix match, so anything volatile placed early in the prompt silently invalidates it. Keep timestamps, request IDs, and per-user context after the cache breakpoint, and verify with usage.cache_read_input_tokens: a persistent zero means something in the prefix changes on every call.
resp = client.messages.create(
model="claude-sonnet-4-5",
max_tokens=1024,
system=[{
"type": "text",
"text": LONG_STABLE_PREFIX, # keep this byte-identical
"cache_control": {"type": "ephemeral"},
}],
messages=messages, # volatile content goes here
)
print(resp.usage.cache_read_input_tokens) # 0 = nothing was reusedStep 4: add cross-provider fallback routing
Backoff buys seconds; a fallback buys availability. Keep an ordered list of deployments (a second Anthropic model, the same model on a different platform, or another vendor entirely) and walk it when the primary returns 529 after its retry budget is spent.
Two rules keep fallback honest. Fail over only on capacity and overload errors, never on a 400 or 401 that will fail identically everywhere. And record which provider actually served each request: a silent fallback changes cost, latency, and output characteristics without anyone noticing until a bill or an eval score moves.
ROUTES = [
("anthropic", "claude-sonnet-4-5"),
("anthropic", "claude-haiku-4-5"), # cheaper, usually less contended
("openai", "gpt-4o-mini"), # different vendor, different capacity
]
def complete(messages):
last = None
for provider, model in ROUTES:
try:
return call(provider, model, messages), provider, model
except (anthropic.InternalServerError, anthropic.RateLimitError) as e:
last = e # capacity problem: try the next route
continue
raise lastStep 5: take bulk work off the synchronous API
The Message Batches API accepts up to 100,000 requests per batch, returns results within 24 hours (most finish inside an hour), and costs 50% less per token. It runs on its own queue, so it does not compete with your interactive traffic.
Results come back in arbitrary order, so key them by custom_id rather than position. Evaluations, dataset labelling, document enrichment, and nightly summarisation all belong here: moving them off the synchronous path removes a large share of the requests that were meeting 529s in the first place.
batch = client.messages.batches.create(requests=requests)
while True:
batch = client.messages.batches.retrieve(batch.id)
if batch.processing_status == "ended":
break
time.sleep(60)
for result in client.messages.batches.results(batch.id):
if result.result.type == "succeeded":
store(result.custom_id, result.result.message)Fallback routing is what keeps a 529 from becoming an outage, and it is also the moment your cost model quietly changes, because a different model at a different price served the request. Nexus records every agent action and token_usage event at the runtime-hook level, so each fallback is attributable: which agent, which repo, which provider took over, and what the switch cost against the baseline. The same capture surfaces providers nobody sanctioned, so a fallback added during an incident does not become permanent shadow AI.
Explore Swfte NexusCommon questions
- What does overloaded_error mean in the Anthropic API?
- It means Anthropic's own infrastructure is temporarily at capacity and cannot accept your request right now. It is returned as HTTP 529 and has nothing to do with your organization's rate limits or billing, so the fix is retrying with backoff and having a fallback route, not requesting a higher limit.
- Is an Anthropic 529 the same as a 429 rate limit?
- No. A 429 `rate_limit_error` means your own organization exceeded its requests-per-minute or tokens-per-minute budget and comes with a `retry-after` header. A 529 `overloaded_error` is Anthropic-side capacity, affects requests regardless of your usage, and cannot be resolved by raising your limits.
- How should I retry a 529 from Claude?
- Retry the identical request with exponential backoff and full jitter, capped at around a minute and bounded to a handful of attempts. The official SDKs do this automatically for 429 and 5xx responses: raising `max_retries` from the default of 2 to 4 or 5 absorbs most transient overloads without any custom code.
- Does prompt caching help with 529 errors?
- Indirectly, and substantially. Caching a stable prefix cuts the input tokens each request has to process, so calls are cheaper and finish faster, which shrinks the window in which a capacity blip can hit them. Verify it is working by checking that `usage.cache_read_input_tokens` is non-zero on repeat requests.
- Should I fail over to another provider on a 529?
- Yes, once your retry budget for that request is spent, but only for capacity and overload errors, never for a 400 or 401 that will fail the same way everywhere. Log which provider and model actually served each request, because a silent fallback changes cost, latency, and output quality with no other visible signal.