An OpenRouter 429 error means a rate or capacity limit blocked a request. Diagnose the source before retrying, then use bounded backoff and concurrency control.
A 429 is a capacity signal, not a prompt bug
An OpenRouter 429 means a rate or quota boundary rejected the request. It can originate at the gateway, a free-model allowance, or an upstream provider. The right response depends on which limit fired.
Checked October 15, 2026: quotas and headers can change. Use the current limits documentation for live rules.
First capture the evidence
import os, requests
r=requests.post(
"https://openrouter.ai/api/v1/chat/completions",
headers={"Authorization":f"Bearer {os.environ['OPENROUTER_API_KEY']}",
"Content-Type":"application/json"},
json={"model":"openrouter/free","messages":[{"role":"user","content":"Hello"}]},
timeout=(5,30),
)
print("status",r.status_code)
for name in ["Retry-After","X-RateLimit-Limit","X-RateLimit-Remaining","X-RateLimit-Reset"]:
print(name,r.headers.get(name))
print(r.text[:1000])
Record UTC time, request ID, requested and returned model, safe provider metadata, concurrency, streaming state, and usage. Never log the API key or sensitive prompt.
Common causes
| Cause | Clue | Fix |
|---|---|---|
| Per-minute limit | Burst traffic; reset header | Honor wait and reduce concurrency |
| Daily free quota | :free or free router |
Wait for reset or use an approved paid model |
| Upstream provider | Provider metadata; another route works | Allow fallback providers or models |
| Retry storm | Many workers retry together | Add jitter, queueing, and a circuit breaker |
| Oversized parallel job | High concurrency with normal single-call usage | Use a semaphore and backpressure |
Retry without ignoring Retry-After
Use the bounded Python client for a complete implementation. Parse Retry-After as seconds or an HTTP date. If the required wait exceeds your job deadline, stop and queue the job for later; do not shorten the server’s delay and immediately retry. When no usable header exists, apply exponential backoff with jitter and a maximum attempt count.
Control the crowd, not just each request
Backoff helps one caller; a semaphore or queue controls the fleet. Set a fixed worker count, queue depth, per-job deadline, and circuit breaker. Shed low-priority work before critical interactive traffic fails.
Free-model specifics
Free-model daily and per-minute allowances are separate from paid capacity and may count failed attempts. Check GET /api/v1/key for current account status. When a product needs dependable volume, design a reviewed paid fallback rather than an infinite retry loop.
Routing fixes
- Allow multiple eligible providers for the same model.
- Remove an unnecessarily strict provider order.
- Add a reviewed fallback model.
- Log the chosen provider/model and compare quality.
- Do not use fallback to hide a credential, budget, or validation error.
Streaming 429s
A stream may begin with HTTP 200 and later emit an error event. Treat partial output as incomplete and decide whether to replace it, preserve it with a warning, or ask the user to retry. Blind replay can duplicate visible text and cost.
Do not retry these
- 400: fix payload.
- 401: fix key.
- 402: fix credits or spend limit.
- 403: fix permissions or policy.
- 404/413/422: fix resource, size, or validation.
OpenRouter 429 error FAQ
Why does switching models help?
Models and providers can have different capacity. Treat that as evidence and measure quality/cost before making the fallback permanent.
Should I always sleep for Retry-After?
Honor a valid delay within your own deadline; otherwise use exponential backoff with jitter.
Does 429 mean nothing was processed?
Not always. A mid-stream provider failure can happen after partial output. Inspect usage and stream state.
Read next
See the routing guide, fallback guide, and Python client.
Official references
Documentation reviewed 15 October 2026. Examples illustrate the request pattern; confirm model availability and account settings before use. No uptime or performance benchmark is claimed.
