OpenRouter 429 "Provider returned error": what it means and the fix
The 429 that SillyTavern, JanitorAI and every OpenAI-compatible client print the same way. What OpenRouter’s docs say it is, which limit it usually is, and the switch to a key where a failed route is retried before you see it.
What the client prints
HTTP 429{ "error": { "message": "Provider returned error", "code": 429, "metadata": { "raw": "...", "provider_name": "..." } }}What it means
OpenRouter's error reference (read 2026-10-31) lists 429 as "You are being rate limited", 502 as "Your chosen model is down or we received an invalid response from it" and 503 as "There is no available model provider that meets your routing requirements". The words "Provider returned error" are the message text; the metadata names the provider in provider_name and carries its verbatim payload in raw.
Two limits produce it. The provider's own: the model's host refused the request and OpenRouter passed the status through. And OpenRouter's: its limits page (2026-10-31) lists 20 requests a minute on free models, 50 free-model requests per UTC day for accounts with under 10 credits purchased and 1,000 with at least 10, and says a negative balance fails requests, free models included.
A 402 is the other near neighbour: the same page defines openrouter_key_limit as the key's credit limit exhausted and openrouter_credits as a balance that cannot cover the request.
The retry rule
"Rate limits are transient; wait and retry rather than immediately re-sending" (OpenRouter's limits page, 2026-10-31). Back off with jitter and read a Retry-After header when one is present; the page says the in-flight-budget 402 carries one.
A 429 whose provider_name is set will repeat for as long as that provider is limited, because the retry goes to the same place. A daily cap on free models will not clear until the UTC day does.
The fix is a request that has somewhere else to go: another route for the same model, then another model, chosen before the error is yours.
A key that fails over, with limits you set
A retry loop treats the symptom. On this key the next route is tried before the error reaches you, every limit is per key, and a failed request costs nothing. From the OpenAPI document, read 2026-10-31.
- Failover before you see it
- A route that fails with a 5xx or a 429 is retried on the next route for the same model. x-uplink-attempts on the answer counts the tries; the price is the model’s own either way.
- Your own fallback list
- models: [...] names up to 5 models tried in order once every route of the one before has failed before a byte was sent. Each bills at its own price when it answers.
- Failed requests are not charged
- A 429, 502 or 503 from this API charges nothing and carries retry-after: back off that long before trying again.
- Limits per key, set by you
- rpm from 1 to 100,000, tpm from 1 to 50,000,000 and concurrency from 1 to 10,000 on each key. Default: 600 requests a minute per key, 50 in flight per account.
- A budget per key
- budget_usd plus a daily, weekly or monthly spend limit. The key stops at its own line with a 402; the rest of the balance is untouched.
- One request id
- x-uplink-request-id on every answer, errors included. Quote it and we find the call.
API route, right now
From GET https://api.relayswitch.io/v1/status, the public feed behind /status, generated 2026-11-02T06:27:20.289Z.
| Service | State | Last check | Latency | Checks today | Failures today |
|---|---|---|---|---|---|
| API | Operational | Nov 2, 2026, 6:07 AM UTC | 884 ms | 7 | 0 |
Every hour the gateway counts the past hour’s real requests to this route: answered or failed. A request answered after a retry counts as answered.
The daily real-model check: 305 of 339 models answered as before, generated 2026-11-02T06:27:20.308Z. Every verdict is on /proof.
The ids this page is about, per million tokens
Four of the ids on this key, read from the catalog at render, with the developer’s list price beside ours where the catalog has it.
| Model | Input | Output | Developer list in / out |
|---|---|---|---|
| Claude Sonnet 5.5claude-sonnet-5-5 | $1.20 | $3.00 | $2.00 / $10.00 |
| GPT-6.1 Solgpt-6.1-sol | $0.60 | $3.00 | $2.00 / $10.00 |
| DeepSeek V4.1 Flashdeepseek-v4.1-flash | $0.06 | $0.18 | $0.30 / $1.20 |
| GLM 5.3glm-5.3 | $0.3276 | $1.0296 | $1.092 / $3.432 |
Read from the catalog at render. A request that fails over bills at the price of the model that answered.
OpenAI SDK: change base_url, keep the client
from openai import OpenAIimport os client = OpenAI( base_url="https://api.relayswitch.io/v1", api_key=os.environ["RELAYSWITCH_API_KEY"],) reply = client.chat.completions.create( model="claude-sonnet-5-5", messages=[{"role": "user", "content": "Continue the scene."}], extra_body={"models": ["gpt-6.1-sol", "deepseek-v4.1-flash"]}, # tried in order if claude-sonnet-5-5 fails)print(reply.model) # the model that answered; billed at its own priceEvery OpenAI-compatible client takes a base URL and a key, so the switch is those two values. models is this API's fallback list, up to 5 ids tried in order; the answer names which one replied in model, and x-uplink-attempts says how many routes it took.
In SillyTavern or JanitorAI, pick the OpenAI-compatible or custom endpoint, paste the base URL and the key, and type the model id. The roleplay page lists the uncensored builds on the same key.
Questions
From what people ask about this error.
A key that does not stop at one host
Failover at the same price, limits and a budget per key, failed requests not charged. Card or crypto, no KYC, no subscription.