
429 Rate Limit vs insufficient_quota: How to Tell Them Apart and Fix Each
Figures on this page were verified 31 August 2026 against the providers' own documentation. Pricing, context windows and rate limits change without notice, so confirm any number against the provider before you rely on it. Tell us if something here is out of date.
A 429 from an LLM API means one of two completely different things, and treating them the same is the most common mistake here. Either you sent requests faster than your tier allows, which you fix by backing off and retrying, or your account has no credit, which retrying will never fix. Read the error code before you write a single line of retry logic.
Two errors, one status code
| What you see | What it means | Retry? |
|---|---|---|
OpenAI rate_limit_exceeded | Too many requests or tokens per minute | Yes, with backoff |
OpenAI insufficient_quota | Billing. No credit on the account | Never. Add funds |
Anthropic rate_limit_error | Too many requests or tokens per minute | Yes, with backoff |
This is why generic “retry on 429” middleware causes trouble. Against insufficient_quota it will retry forever, burn your timeout budget, and report a rate-limit problem to your monitoring while the real cause is an empty wallet. Branch on the code, not the status.
What you are actually being limited on
Rate limits are enforced on more than one axis at once, and you trip whichever you reach first:
- Requests per minute. How often you call, regardless of size.
- Tokens per minute. The total volume you push through. A handful of very large prompts can exhaust this while your request count looks harmless.
- Concurrency. How many calls are in flight simultaneously.
The token axis is the one that surprises people. Ten requests a minute sounds conservative until each carries a 200,000 token document. Reserved output tokens count toward the token budget too, so an over-generous max_tokens inflates your consumption even when the model replies briefly.
Read the response headers before guessing
Both providers tell you what is left and when it resets. Guessing a sleep interval when the server has already told you the answer is wasted latency.
retry-after seconds to wait anthropic-ratelimit-requests-remaining calls left this window anthropic-ratelimit-tokens-remaining tokens left this window anthropic-ratelimit-requests-reset when the window resets x-ratelimit-remaining-requests OpenAI equivalent x-ratelimit-remaining-tokens OpenAI equivalent
If retry-after is present, honour it. It is authoritative and beats any backoff curve you invent.
Retry properly: exponential backoff with jitter
Fixed-interval retries from many workers re-synchronise into a thundering herd that trips the limit again the moment it clears. Randomised backoff spreads them out.
import random, time
import anthropic
client = anthropic.Anthropic()
def call_with_backoff(fn, max_attempts=6):
for attempt in range(max_attempts):
try:
return fn()
except anthropic.RateLimitError as e:
if attempt == max_attempts - 1:
raise
# Honour the server's own guidance when it gives it.
wait = getattr(e, "response", None) and e.response.headers.get("retry-after")
delay = float(wait) if wait else (2 ** attempt)
time.sleep(delay + random.uniform(0, 1)) # jitter
Catch the specific exception class rather than a broad one. A single except around every API error will retry malformed requests that can never succeed, which is the same bug as retrying insufficient_quota.
Reduce the pressure instead of absorbing it
- Batch offline work. If a job is not interactive, batch endpoints run outside your synchronous limits and cost less. Anthropic’s Batch API runs at 50% of standard pricing.
- Trim what you send. Token-per-minute limits are consumed by prompt size. Shorter prompts mean more requests fit in the same budget.
- Cap concurrency yourself. A queue with a fixed worker count is more predictable than firing everything at once and catching the fallout.
- Set max_tokens realistically. Reserved output counts against you.
- Spread scheduled jobs. Cron tasks that all fire on the hour create an avoidable spike.
If it is a quota problem
There is no code fix. insufficient_quota means the account has no usable credit, and no amount of backoff changes that. Check billing, confirm the payment method, and verify you are using the API key for the organisation you funded. Keys from a different org fail this way even when that org has credit.
Surface it as a distinct alert. Paging an engineer for a rate limit that is really an unpaid invoice wastes everyone’s evening.
Related
If you are hitting token-per-minute limits, prompt size is your lever, and the same arithmetic drives your bill. Our LLM API cost calculator shows what a given workload costs across providers. For the related failure where a single request is too large, see context_length_exceeded.
This page is part of our LLM API error reference, which covers every common error across OpenAI and Anthropic and whether each one is safe to retry.
Frequently asked questions
How do I tell rate_limit_exceeded from insufficient_quota?
Read the response body, not the status code, because both arrive as a 429. rate_limit_exceeded, or Anthropic's rate_limit_error, means you sent requests too quickly and should retry with backoff. insufficient_quota means you have no credit or have hit a billing hard limit, and no amount of retrying will clear it.
What backoff should I use for a 429?
Exponential with full jitter: sleep for a random interval between zero and base times two to the power of the attempt number, capped at around 60 seconds, with a maximum attempt count. If a Retry-After or anthropic-ratelimit reset header is present, honour it, because that is the provider telling you exactly when to return.
Do rate limits apply per key or per organisation?
Per organisation and per model tier on both OpenAI and Anthropic, not per key. Issuing more keys does not raise the ceiling. If you need genuine isolation between workloads, separate them by project or organisation instead.


