A 429 from an AI API means you exceeded a limit, but not always the one you think. It can be a per-minute rate limit, a sharp-growth acceleration limit, or a monthly spend cap. The retry-after header and the error details tell you which, and the right fix differs for each.
Three causes behind one status code
Anthropic's documentation describes two kinds of limits: spend limits set a maximum monthly cost, and rate limits set the maximum number of requests over a period. It also mentions acceleration limits, which can trigger when usage rises sharply. All of these can surface as a 429.
| Cause | Typical sign | Fix |
|---|---|---|
| Rate limit | retry-after header present, clears within seconds | Back off, smooth traffic, cache, queue |
| Acceleration limit | Errors after a sudden traffic jump | Ramp up gradually, keep usage steady |
| Spend cap | No retry-after, error details name a spend limit | Raise the cap, wait for the next period, or fix the cause of spend |
The spend cap is the dangerous one
The documentation says that once you reach a tier's monthly cap, usage pauses until the first day of the next month unless you request a higher limit. The response is a 429 with the same error type as a rate limit, but with no retry-after header, and the SDK's automatic retries fail until access resumes. A code path that treats every 429 as transient will loop against a wall.
The error body carries a code that separates the two. On the Messages API the documentation names it as enforced_spend_limit_reached. Branch on that field, not on the status alone.
If you set your own lower limit, the behavior differs again. The same page says requests then return HTTP 400 with an invalid request error whose message begins by saying you reached your specified usage limits. So a self-set cap and a tier cap look different to your code.
A triage routine
- Read the response headers. Look for retry-after and the remaining and reset fields for requests and tokens.
- Read the error body for a code that names a spend limit.
- Check the usage page in your provider console for the last hour. Was there a spike?
- If it is a rate limit, apply backoff with jitter and look at whether one service is hogging the pool.
- If it is a spend cap, stop retries and alert a human, because the next retries only add load.
- Find out why spend rose before you raise the cap. A runaway loop or a leaked key looks the same as growth until you check.
Raising a cap without finding the cause is how a small incident becomes a large invoice. The cost anomaly runbook walks through that investigation.
Make your client tell them apart
A small amount of code pays off. Classify errors into retry later, retry never, and page someone. A spend cap error belongs in the second or third group. A rate limit with a retry-after value belongs in the first, using that value as the wait. OpenAI's guidance says to respect Retry-After when present, use exponential backoff with jitter otherwise, cap attempts and total retry time, and not retry quota or billing errors.
Log the error code alongside the request ID so you can answer later which service hit which limit.
Worked example: three incidents, three fixes
These scenarios are illustrative.
Incident one: a sudden launch. A feature goes live at noon and traffic jumps within minutes. Errors begin at once, and most responses carry a retry-after header. This is a rate limit, possibly an acceleration limit. The fix is a queue with a concurrency cap, a gradual rollout, and a request for higher limits ahead of the next launch.
Incident two: the quiet month end. On the 27th, every call starts failing, no response carries a retry-after header, and the error body names a spend limit. Your SDK retries each call several times, which only adds load. The fix is to stop retries on that error code, page the owner, and check the usage page for a spike before raising anything.
Incident three: a limit you set yourself. After a finance review, someone sets a low monthly limit. Requests begin to return HTTP 400 rather than 429. Teams that only watch for 429 miss it, and customers see a generic failure. The fix is to alert on the 400 error type that names your specified limit, and to document who set the limit and why.
What to log for each error
Record these fields so triage takes minutes:
| Field | Why |
|---|---|
| HTTP status | First split between rate and cap |
| Error type and code | Tells a spend cap from a rate limit |
| retry-after value | Whether waiting will work |
| Request ID | Lets the provider find the call |
| Workspace or key name | Which service hit it |
| Model | Limits are per model class |
Alert design
Page a human for spend cap errors, since nothing automatic will fix them. Ticket rate limit errors when they exceed a small share of requests over ten minutes. Chart daily spend against a rolling baseline so you see the climb before the wall.
Communicating with users during a limit
A good error message depends on the cause. For a rate limit, show a short "busy, trying again" state and retry quietly. For a spend cap, do not pretend it is temporary. Show a clear unavailable notice, route the user to a fallback such as a saved draft or a human, and alert your team. Customers forgive a clear message far faster than a spinner that never ends.
Write the three messages in advance, with owners for each, and test them in staging by forcing each error from a stub.
A short decision tree
Start with the header. If a retry-after value is present, wait that long and retry once, then use backoff. If it is absent, read the error code. A code that names a spend limit means stop. If the message names a limit you set yourself, you will see a different status, so check that too. If you are unsure, treat the error as non-retryable and alert a human, because a wrongly retried spend error wastes effort while a wrongly abandoned rate limit error only delays one job.
Teach the tree to everyone who writes AI integrations. Put it in your service template so each new project starts with the right classification. Add a test that feeds the three error shapes through the client and checks the decisions.
What this means for you
A 429 is not one problem. Read the headers and the error body before you react. Waiting fixes a rate limit. Nothing automatic fixes a spend cap, and retrying it only adds noise. Teach your code to tell them apart and your team to page a person for the second kind.
Common mistakes
Typical mistakes are retrying every 429, trusting an SDK's automatic retries to handle a spend cap, raising a cap without checking why spend rose, alerting only on one status code and forgetting that a limit you set yourself reports differently. Log the error code, classify the error, alert the right person and investigate before raising anything.
Try it yourself
Click through it at your own pace, or open it full screen. It shows monitoring that watches a system over time and raises an alert on change. Look for how a steady baseline makes a spike stand out, which is the same idea behind alerting on daily spend.
Quick check
Should I retry every 429?
No. Retry rate limit errors using the retry-after value or backoff with jitter. Do not retry spend cap or billing errors, because they will not clear until the cap resets or is raised.
Why is there no retry-after header on my 429?
Anthropic documents that the spend cap 429 never carries one. Other 429 causes may also omit it, so use backoff.
Is a self-set limit reported the same way as the tier cap?
Not on the provider documented here. A self-set limit returns HTTP 400, while the tier cap returns 429. Check your provider's current docs.
Sources
Last reviewed: 19 October 2026.