Errors
HTTP status codes, error envelopes, and recommended retry behavior for every AnyRouter API error.
Errors
AnyRouter uses standard HTTP status codes and wraps every error in an OpenAI-compatible envelope:
JSON
json
{
"error": {
"message": "Human-readable message",
"type": "error_category",
"code": "machine_code",
"param": "optional_request_field"
}
}Status codes
| Status | Type | Retry? | Description |
|---|---|---|---|
400 | invalid_request_error | No | Malformed request — fix and re-send. |
401 | authentication_error | No | Missing or invalid API key. |
403 | permission_error | No | Key lacks the required scope. |
404 | not_found_error | No | Model or resource does not exist. |
409 | conflict_error | No | Conflicting state (e.g. duplicate key name). |
413 | request_too_large | No | Input exceeds the model's context window. |
422 | invalid_request_error | No | Request shape is valid but semantically wrong. |
429 | rate_limit_error | Yes, with backoff | Rate limit hit — honor Retry-After. |
499 | client_closed_request | No | Client disconnected before response. |
500 | internal_server_error | Yes | AnyRouter internal issue. |
502 | upstream_error | Yes | Upstream provider returned a 5xx. |
503 | service_unavailable | Yes | No healthy upstream available. |
504 | upstream_timeout | Yes | Upstream provider timed out. |
Retry strategy
For retryable errors (429, 5xx), use exponential backoff with jitter:
TYPESCRIPT
typescript
async function withRetry<T>(fn: () => Promise<T>, attempts = 5): Promise<T> {
for (let i = 0; i < attempts; i++) {
try {
return await fn()
} catch (err) {
if (i === attempts - 1) throw err
if (!isRetryable(err)) throw err
const base = Math.min(1000 * 2 ** i, 30_000)
const jitter = Math.random() * 250
await new Promise((r) => setTimeout(r, base + jitter))
}
}
throw new Error("unreachable")
}Honor the Retry-After response header when present — it tells you exactly how long to wait before the next attempt.
Warning
Never retry 4xx errors other than 429. A 401 will keep returning 401 until you fix the auth header; retrying just burns rate-limit budget.
Common error codes
| Code | Meaning |
|---|---|
invalid_api_key | The Authorization header didn't match any AnyRouter key. |
insufficient_credits | The account has run out of credits. Top up to continue. |
model_not_found | The requested model slug doesn't exist in the catalog. |
context_length_exceeded | Input is longer than the model supports. |
rate_limited | Per-key or per-org rate limit exceeded. |
upstream_unavailable | All upstream providers for this model are down. |
content_policy | Upstream refused the request due to a content-policy filter. |
Debugging
Every response includes an X-AnyRouter-Request-Id header. Include it when reporting bugs — it lets us find your exact request in the audit log.
BASH
bash
curl -i https://anyrouter.dev/api/v1/chat/completions \
-H "Authorization: Bearer ar-your-key" \
-H "Content-Type: application/json" \
-d '{"model": "openai/gpt-4-turbo", "messages": [{"role": "user", "content": "hi"}]}'
# HTTP/2 200
# x-anyrouter-request-id: req_01HQ...