Docs
Errors and failover
Every error has an HTTP status and a machine-readable code. Some errors are handled before you see them: when the route serving a request fails, the same model is tried on another route.
Error format
{
"error": {
"message": "Insufficient credits.",
"type": "insufficient_balance",
"code": "insufficient_balance"
}
}/v1/chat/completionsand/v1/responsesuse the OpenAI shape above; some errors addparam.- Authentication and limit errors use
{"error": {"code": ..., "message": ...}}. /v1/messagesuses Anthropic's envelope with the same HTTP status and message. See Messages.
Authentication and limits
| Status | Code | Meaning |
|---|---|---|
| 401 | missing_api_key | No key in Authorization or x-api-key. |
| 401 | invalid_api_key | The key is not recognized. |
| 403 | disabled_api_key | The key is disabled. Enable it or create a new one in the console. |
| 403 | expired_api_key | The key has passed its expiry date. |
| 403 | organization_frozen | The organization is frozen or disabled. Contact support. |
| 429 | org_rate_limit_exceeded | More than 600 requests in one minute across the organization. Retry after the seconds in the retry-after header. |
| 429 | key_rate_limit_exceeded | The per-minute limit you set on this key in the console was hit. Keys without a limit only count toward the organization's 600. Retry after the seconds in the retry-after header. |
| 429 | key_spend_limit_exceeded | The key reached the daily or monthly spend limit set in the console. Raise it, or wait: retry-after points to the next UTC day or month. |
Request and balance errors
| Status | Code | Meaning |
|---|---|---|
| 400 | invalid_request | The body does not match the endpoint's format, for example a missing model or n other than 1. |
| 400 | unsupported_parameter | A field that cannot be served, such as audio, store: true or previous_response_id. param names it when there is one. |
| 400 | model_not_found | The model id is not in the catalog. |
| 400 | context_length_exceeded | The input is over the model's limit. The message gives the limit and the estimate. |
| 400 | model_price_not_configured | The model cannot be billed right now. Contact support. |
| 402 | insufficient_balance | The balance cannot cover the request. See Balance and max_tokens. |
| 400 | byok_credential_required | The model runs only on your own key, and no usable key for its lab is on the account. |
| 402 | byok_quota_exhausted | The monthly BYOK request allowance is used up on a model that runs only on your own key. It resets on the 1st of the month (UTC). |
| 400 | byok_billing_config_incomplete | This BYOK-only model cannot be billed right now. Contact support. |
Errors from the model's route
| Status | Code | Meaning |
|---|---|---|
| 502 | provider_error | The model's service failed, on every route tried. |
| 504 | provider_timeout | The request ran out of time. See Time limits. |
| 429 | provider_rate_limited | The model's service is rate limiting, on every route tried. Retry with backoff. |
| 4xx | provider_invalid_request | The model's service rejected the request itself, for example an argument the model does not accept. The status and message are passed through as received. |
Where the model's service returned its own wording, message keeps it, so client libraries that react to specific messages, such as context-length recovery, keep working.
Failover
When the route serving a request fails, BoostRail tries the same model on another route before anything is sent to you. It never switches to a different model.
- Moved to another route: server errors, rate limiting, and the route refusing BoostRail's own access.
- Not moved:
provider_invalid_request, because another route would reject the same request, and non-streaming timeouts, because a request that ran out of time would run out again. - Streaming: if no first event arrives within 45 seconds, the request moves to the next route. The last route tried has no first-event limit.
- Once any data has been sent to you, the request is not moved.
- When every route fails, you get the error from the last attempt, the reservation is released, and nothing is charged.
- A route that failed is tried last by later requests until it succeeds again.
A streaming request that breaks after data was sent is billed as described on the Pricing page.
Time limits
| Request | Limit | What happens |
|---|---|---|
| Non-streaming | 180 seconds | 504 provider_timeout. Not moved to another route. |
| Streaming, first event | 45 seconds per route | Moves to the next route; the last route has no first-event limit. |
Session affinity
Requests that share a session id are kept on the route that served the session's last successful request when it can, which helps prompt caching. The session id is read, in order, from the x-claude-code-session-id header, the x-session-id header, then user (Chat Completions and Responses) or metadata.user_id (Messages).
When to retry
- 400 and 402: fix the request or the balance first. Retrying unchanged gives the same result.
- 429 with
retry-after: wait that many seconds. - 502, 504 and
provider_rate_limited: retry with exponential backoff. Failover has already been tried on BoostRail's side. - Include the
x-request-idvalue when you contact support.