Errors Code
SIRAYA Model Router uses standard HTTP response codes to indicate the success or failure of an API request. In case of an error, the response body will contain a structured JSON object with details.
Error Response Format
Errors are returned as a JSON object with the following schema:
{
"error": {
"message": "no vendors found for model: unknown-model",
"type": "invalid_request_error",
"code": "model_not_found"
}
}
Fields
| Field | Type | Description |
|---|---|---|
message |
string | Human-readable description of the error. Vendor-internal identifiers (request IDs, ARNs, cloud resource paths) are removed on a best-effort basis. |
type |
string | Error category, useful for branching client-side logic. Not present on errors returned before routing (see below). |
code |
string | number | Specific identifier. A string for errors returned after routing (a routing code such as model_not_found, or the same value as type), or the numeric HTTP status for errors returned before routing. |
Errors returned before routing
API key, credit, rate-limit and request-body checks run before the request is routed to a model. These errors carry only message and a numeric code, with no type:
| Code | message |
When |
|---|---|---|
| 401 | Unauthorized |
The Authorization header is missing, or the API key is invalid. |
| 402 | Your account or API key has insufficient credits. Add more credits and retry the request |
The account or API key is out of credits. |
| 403 | Forbidden to use this Model |
The API key is disabled or expired, or is not allowed to use the model. |
| 409 | Bad Request Contents |
The body of a POST request is not valid JSON. |
| 429 | Too Many Requests, Reach the limit of requests per minute |
The account's rate limit was reached. See the Retry-After header. |
Every POST endpoint takes a JSON body. A body that fails to parse returns 409 and is not routed. Sending an empty body may return a non-JSON 500 page instead, so check the status code before parsing the body.
The API key is read from Authorization: Bearer <API_KEY>. The x-api-key header is also accepted, so the Anthropic SDKs work unchanged.
Rate limits
The 429 above is your own account's limit, applied per account across all of its API keys, to requests and tokens within a time window. It carries these headers:
| Header | Meaning |
|---|---|
Retry-After |
Seconds until the current window ends. |
X-RateLimit-Limit-Requests |
Request limit for the window (0 means unlimited). |
X-RateLimit-Limit-Tokens |
Token limit for the window (0 means unlimited). |
X-RateLimit-TimePool |
Window length in minutes. |
Wait for Retry-After before retrying.
Common Error Codes
These are returned after routing, and include type. For 5xx responses type follows the status and code carries the same value.
| Code | Status | Description |
|---|---|---|
| 400 | Bad Request | Invalid parameters. type is one of invalid_request_error, context_length_exceeded, content_policy_violation, rejected_request_error, unsupported_params_error. |
| 401 | Unauthorized | Upstream credentials were rejected. type is authentication_error. |
| 403 | Forbidden | The API key lacks permission for the requested routing pool. type is permission_denied_error (or permission_denied with code=pool_access_denied for routing errors). |
| 404 | Not Found | The requested model or resource does not exist. type is not_found_error, or invalid_request_error with code=model_not_found for routing errors. |
| 408 | Request Timeout | The upstream provider reported a timeout. type is timeout_error. |
| 422 | Unprocessable Entity | The request was well-formed but semantically invalid. type is unprocessable_entity_error. |
| 429 | Too Many Requests | The upstream provider throttled the request. type is rate_limit_error. This is separate from your account's limit above; when every route is throttled the response is 503 instead. |
| 500 | Internal Server Error | Unhandled error in the router or upstream provider. type is internal_error. |
| 502 | Bad Gateway | The connection to the upstream provider failed. type is api_error. |
| 503 | Service Unavailable | No route is available: no vendor, all vendors cooling down, or the failover/fallback budget was exhausted. type is service_unavailable, with a routing code such as no_vendors_available, all_vendors_cooling_down, max_failovers_exceeded or max_fallbacks_exceeded. |
| 504 | Gateway Timeout | The upstream provider did not respond within the request time budget. type is api_error. |
Other error formats
-
POST /v1/messagesreturns the Anthropic error envelope, with nocodefield:error.typeisinvalid_request_error,authentication_error,permission_error,not_found_errororrate_limit_error, andapi_errorfor everything else. Errors returned before routing keep the format shown above. -
Async image requests (
async: true) that are rejected, for example without a validcallbackUrl, return{"created": …, "data": {}, "error": {"message": "…"}}. -
Asset Management and External Console API (on the portal host) use their own envelope with
isSuccessand upper-case error codes. See Asset Management and External Console API.
Handling Errors
When using the OpenAI SDK or standard HTTP clients, always check the response status code. Some errors (an empty request body, a failed connection) return a non-JSON body, so do not assume the body parses.
const response = await fetch('https://llm.siraya.ai/v1/chat/completions', { /* ... */ });
if (!response.ok) {
const text = await response.text();
let error = {};
try {
error = JSON.parse(text).error ?? {};
} catch {
// Non-JSON body: fall back to the raw text.
}
// `type` may be missing and `code` may be a string or a number, normalize both
const code = String(error.code ?? '');
const type = error.type ?? '';
console.error(`[${response.status}] ${type} (${code}): ${error.message ?? text}`);
}
Warm-up and Retries
Occasionally, a model may not generate content immediately during provider warm-up or scaling. We recommend implementing a retry mechanism with exponential backoff for 5xx and 408 errors, and honouring Retry-After on 429.
Do not retry a 503 whose message says the upstream provider refused every available route because of rate limiting or an exhausted quota: retrying will not help, so contact support instead.