Troubleshooting
401 invalid_api_key
- Key was revoked (Workspace → API keys → Key activity shows the event).
- Key was copied incompletely (it starts
sk_live_orsk_test_; both work the same way). - Wrong header (must be
Authorization: Bearer …).
400 model_not_allowed
The workspace allowlist is on and the requested model isn't in it. Either add the model under Routing → Allowed models or call a model that's already allowed.
400 unknown_model
The slug isn't in the catalog. Check spelling. List allowed models via the dashboard.
503 no_vendor_key
No usable credential for the vendor that owns this model right now. Retry later or send another model; if you bring your own vendor keys, check them under Organisation → Vendor keys.
402 budget_exhausted
The message says which: prepaid credit is used up, a workspace or organisation budget cap is reached, or the odnoga subscription is not active. Top up or fix billing in Pay odnoga, raise the cap, or wait for the budget window to reset (x-ratelimit-reset, when a window exists).
429 (workspace_concurrency_limit, tenant_concurrency_limit, workspace_rpm_limit, workspace_tpm_limit, capacity_unavailable)
A limit was reached before the call went anywhere — nothing was charged. Honour Retry-After. The code says which limit; see Concurrent sessions.
503 vendor_unavailable
A vendor behind odnoga failed or timed out. The message is generic on purpose and x-odnoga-ticket names the ticket already open with the odnoga team. Retry shortly or send another model; a fallback chain does this for you.
503 billing_unavailable
odnoga stopped the call before it reached the model because of a problem on our side with that model. Nothing was sent and nothing was charged. x-odnoga-ticket names the ticket already open with the odnoga team. Retry later or send another model; a fallback chain does this for you.
A 4xx with type upstream_error
The vendor rejected something about your request, and its own message is passed through (the code is the vendor's HTTP status). Fix the request as the message says — retrying the same body will fail the same way.
504 on a long call
Two different things can be behind it, and they need opposite fixes.
The vendor was slow. odnoga gives a model up to 300 s and then fails over to the next one in your chain (or answers 503 vendor_unavailable if none is left). If one model is consistently slow,
switch it or put a fallback policy behind it.
The call was too long to answer in one piece. A non-streamed request has to
produce the whole answer within roughly 150 seconds, because the clock measures
the time until the response starts. Reasoning models at xhigh effort
routinely pass that on a large prompt — and no retry will help, because the
next attempt takes just as long.
If it is your own serverless function timing out rather than the gateway, note
that 150 seconds limits how long you can make a caller wait, not how long the
work may take: respond immediately and continue in EdgeRuntime.waitUntil, and
you get the full wall clock.
Tell them apart by the latency on the request row: a vendor problem varies, a ceiling lands at the same number every time. The fix is to stream it, move it to the Batch API, or lower the effort — see Retries and timeouts.
Headers look fine, analytics are empty
You're not setting x-airouter-end-user. Add it and traffic re-populates Top end users from the next call onward.
Streaming hangs after the first chunk
A proxy in front of your code is buffering. For Nginx: proxy_buffering off. For Vercel: stream with the correct response type.
Costs say $0 on every row
Every row is status = error — there were no tokens to bill. Look at error_code; once the call succeeds, cost populates.
Still stuck?
Grab the x-airouter-request-id from the failing call and share it with support. That row contains everything we need.