Troubleshooting
openai or openrouter shape get { "error": { "message", "type", "code" } }. The anthropic and google shapes get their own SDK's error envelope, so read the message there — the same code shows on the request's row in Logs. Every response carries X-FreeRouter-Request-Id; quote it when you contact support. The envelope per shape is in API Reference → Errors.
Status and code table
| Status | code | Likely cause | Fix |
|---|---|---|---|
| 400 | invalid_json | The body is not valid JSON (unbalanced quotes, a trailing comma, shell quoting). | Validate the body; send Content-Type: application/json. |
| 400 | missing_model / missing_messages | A chat body without model, or with an empty messages array. | Send both fields. |
| 400 | batch_only_model | A :batch model id on a synchronous endpoint. | Submit it to POST /v1/batches, or drop the :batch suffix. |
| 400 | (google envelope) | :streamGenerateContent — streaming is not served on the google shape. | Call :generateContent without streaming, or use an openai-shaped key. |
| 401 | invalid_api_key | No key arrived, or it matched nothing. Common: the env var is empty, the key was pasted with a trailing space, or your SDK sends it in a header FreeRouter does not read. | Send Authorization: Bearer fr_live_…, x-api-key (Anthropic SDK) or x-goog-api-key (Gemini). echo $FREEROUTER_API_KEY first. |
| 401 | revoked_api_key | The key was revoked in the dashboard. | Create a new key. A rotated key keeps answering to its old secret until X-FreeRouter-Key-Grace-Until; a revoked one does not. |
| 402 | no_route | The key has no routing targets. X-FreeRouter-Attempts: 0 — nothing was sent upstream. | Open the key card and route it to a provider. The create form does this for you under Route this key to. |
| 402 | all_targets_failed | Every target answered 402: the gateway account behind your provider key is out of credit. X-FreeRouter-Attempts is 1 or more. | Add credit on the gateway, or send a free model such as openrouter/free. |
| 403 | ip_not_allowed | An IP allowlist (workspace or key) does not admit the caller. The message echoes the address FreeRouter saw. | Add that address under Settings or on the key — see IP allowlists. |
| 403 | workspace_suspended | The workspace is suspended. | Contact support. |
| 404 | wrong_api_shape | The endpoint does not match the key's shape — for example /v1/messages with an openai key, or /v1/chat/completions with an anthropic key. | Call the shape's own endpoint, or create a key with the shape your SDK speaks. See API shapes. |
| 404 | model_not_available | None of the providers the routing rule picked list that model. Nothing was sent; the message names gateways that do list it. | Add such a provider to the key's rule, or add a model remap. |
| 404 | model_not_found | A gateway was asked and said the model does not exist. The message relays the gateway's text. | Check the id against GET /v1/models for that key. |
| 404 | not_found | A path FreeRouter does not serve: /v1/completions, /v1/files, /v1beta/…. | See what is not supported. |
| 409 | response_chain_target_unavailable | A previous_response_id is pinned to a provider that is no longer on the key. | See Responses chaining. |
| 413 | request_too_large | The JSON body is over 10 MB. | Send files by URL, or split the request. |
| 429 | rate_limited | Every target answered 429. Retry-After is forwarded when the gateway sent one. FreeRouter itself has no rate limit. | Back off and retry; add a second provider so the next 429 fails over instead. |
| 499 | client_closed (Logs only) | Your client hung up before the response finished — usually an HTTP client timeout shorter than the model's answer. The Status column is that outcome. A hop in the expanded route can still show 200: that badge is the gateway's HTTP status, from before the client left. | Raise the client timeout, or stream so bytes arrive early. Nothing is sent as HTTP 499. |
| 501 | gateway_not_supported | None of the key's providers can serve this endpoint (for example a Decisions-only host on a chat key). | Route the key to a chat gateway from Providers. |
| 501 | embeddings_unsupported | /v1/embeddings: none of the gateways the routing rule picked has an embeddings route, so nothing was sent. Each was skipped as no-embeddings; the message names the gateways that do serve embeddings. | Add one of those providers to the key's rule — see API Reference → embeddings. |
| 502 | provider_auth_failed | The gateway rejected your stored provider key (401 upstream). Your FreeRouter key was fine. | Re-paste the provider key under Providers. |
| 502 | upstream_unreadable | The gateway closed the connection before a body arrived. | Retry. If it repeats, check that gateway's status page and the row in Logs. |
| 502 | stream_aborted | A stream was cut off mid-way. Arrives as one data: {"error": …} record inside the stream, after a 200. | Retry. Read the last chunk's error before treating a stream as complete. |
| 502 | no_healthy_target | Every target was unusable before a request was sent (no decryptable provider key). | Check the providers on the key's rule. |
| 502 / 5xx | all_targets_failed | Every target failed; the last gateway's status is relayed (402, 403, 5xx). | Read X-FreeRouter-Failover for the per-gateway reason, then retry. |
| 503 | gateway_disabled | FreeRouter has switched that gateway off platform-wide. | Wait, or add another provider to the rule so traffic fails over. |
| 504 | deadline_exceeded | The 95 s request deadline ran out before any gateway answered: the targets tried so far used up the time, and the last attempt was cut short or never started. X-FreeRouter-Failover shows deadline on it. | Put a faster target first, or give the slow one a shorter failover timeout so the next target gets its turn sooner. |
| 500 | internal | Something broke inside FreeRouter. | Retry; report the X-FreeRouter-Request-Id. |
Reading the failover headers
Three response headers say what the router did. They are on error responses too.
| Header | Meaning |
|---|---|
X-FreeRouter-Provider | The gateway that answered. Absent when nothing was sent upstream (no_route, wrong_api_shape, auth errors). |
X-FreeRouter-Attempts | How many upstream calls were made. 0 means the request never left FreeRouter; 2 or more means at least one failover. |
X-FreeRouter-Failover | Only present after a failover: gateway:reason for each losing attempt, comma-separated, for example openrouter:ttfb-timeout,vercel:rate-limited. |
Reasons: ttfb-timeout (no first byte within the failover timeout), timeout (upstream timeout), deadline (the 95 s request deadline cut this attempt short, or it was never started), unreachable, client-closed, not-listed (the gateway's catalog lacks the model, so it was skipped), batch-only, no-embeddings (the gateway has no embeddings route, so /v1/embeddings skipped it), no-model (the gateway said 404), rate-limited (429), provider-auth (401 — fix that provider key), server-error (5xx), http-NNN for anything else. The same chain is drawn on the request's row in Logs. Why a 402 or 404 fails over, and what a rule can hold, is in Routing Rules → Why failover triggers and rule limits.
My first request returned 402
Two different things return 402. Tell them apart with code and X-FreeRouter-Attempts:
no_route,Attempts: 0— the key is not routed to any provider. Open the key card and tick a provider under Route this key to.all_targets_failed,Attempts ≥ 1— the gateway relayed its own 402: the account behind your provider key has no credit. New gateway accounts usually start empty. Either add credit there, or make your first call withopenrouter/free, which answers on any OpenRouter key.
The Anthropic SDK gets 401 or 404
- 401 — the SDK sends the key as
x-api-key, which FreeRouter accepts. Check thatapi_key(orANTHROPIC_API_KEY) holds thefr_live_…key, not your Anthropic key. - 404
wrong_api_shape— the key's shape isopenai. The Messages endpoint needs ananthropic-shaped key. - 404
not_found— the base URL has/v1on it. The Anthropic SDK appends/v1/messagesitself, so setbase_urltohttps://api.freerouter.comwith no path.
Working snippets for both SDKs and Claude Code are in Use your SDK.
Streaming stops after about 100 seconds
Cloudflare sits in front of api.freerouter.com and closes a connection that has carried no bytes for roughly 100 s (HTTP 524). FreeRouter sends nothing until the gateway's first byte, so the upstream timeout is capped at 90 s to stay under that limit. On the anthropic shape FreeRouter emits a ping event after 10 s of silence to keep long thinking alive; chat streams carry only what the gateway sends. If a model is silent for over 100 s on a chat stream, the connection drops — use a shorter prompt, a faster model, or the anthropic shape. A request that is still failing over at that point does not get there: the whole request is bounded by a 95 s deadline, so a rule with several slow targets answers 504 deadline_exceeded (with deadline in X-FreeRouter-Failover) instead of a Cloudflare 524 with no headers at all. Timeouts are per key: see Routing Rules → Timeouts.
It works in Playground but not from my app
Playground and the Test key button run from the dashboard and are never written to Logs, so a request from your app is the first one FreeRouter sees. Check, in order:
- Logs → filter Errors (400+). If the row is there, its explanation says what failed and links the fix.
- No row at all: the request never reached FreeRouter — wrong base URL (
/v1missing or doubled), a proxy, or DNS. Try the curl from the key card. - Different IP: an IP allowlist admits your laptop but not the server. The 403 names the address.
- Different model id: Playground picks from the key's catalog; your app may send one no target lists (
model_not_available).
Where to look in Logs
- Logs open on the last 7 days. Set the status filter to Errors (400+).
- A failed row carries a one-line explanation and a link to the fix (the provider, the key's routing, the allowlist). Rejections FreeRouter made before sending anything show provider None.
- Expand a row for the attempt path: each gateway tried, its status, and the timing budget that cut it.
- Playground runs and Test key never appear here. Details: Usage & Spend.