Errors
Errors use HTTP status codes and a JSON body:
{
"error": {
"message": "Rate limit of 600 requests a minute reached for this key.",
"type": "rate_limited",
"code": "ORYX_4292",
"request_id": "req_..."
}
}typeis stable and machine-readable; branch on it.codeis a specific ORYVOX code (ORYX_xxxx) to quote to support.request_ididentifies the request in the log (also inX-Oryvox-Request-Id).
Error types
| Status | type | When | SDK class | Retried by SDKs |
|---|---|---|---|---|
| 400 | invalid_request | Missing or invalid fields (e.g. no messages, no input). | ValidationError (BadRequestError) | No |
| 400 | blocked_by_policy | The project policy stopped secrets or personal data in the prompt. | ValidationError | No |
| 400 | bad_request, context_too_long | A provider refused the request, or it does not fit the context. | ValidationError | No |
| 401 | invalid_api_key | Missing, unknown, expired or revoked key. | AuthenticationError | No |
| 402 | budget_exceeded | A project, key or workflow budget is reached. | BudgetExceededError | No |
| 402 | insufficient_credits | Prepaid credit (or the postpaid credit limit) does not cover the request. | InsufficientCreditsError (subclass of BudgetExceededError) | No |
| 402 | plan_limit | Live keys: the company's Core plan request allowance for the month is used up (Free: 10,000 requests). | BudgetExceededError | No |
| 403 | permission_denied | The key lacks the endpoint's scope. | PermissionDeniedError | No |
| 403 | ip_not_allowed | The caller's IP is not on the company or key allowlist. | PermissionDeniedError | No |
| 404 | model_not_found | Unknown model (or not an embedding model). | NotFoundError | No |
| 404 | not_found | Unknown request id in this project. | NotFoundError | No |
| 409 | conflict | ORYX_4091: a request with this Idempotency-Key is still running. ORYX_4092: it already ran and its result was not kept (streamed, or Zero retention). | ConflictError | ORYX_4091 yes, ORYX_4092 no |
| 422 | idempotency_mismatch | The Idempotency-Key was used with a different body. | ValidationError | No |
| 429 | rate_limited | ORYX_4292: the key's requests-per-minute limit. ORYX_4291: every provider route was rate limited after fallbacks. | RateLimitError | Yes |
| 502 | provider_error, invalid_response, auth | Every attempt failed: provider error, unusable answer, or the provider rejected its key (e.g. a BYOK key). | InternalServerError | Yes |
| 503 | no_model_available, provider_unavailable | No allowed model can serve it, or providers are down. | ProviderUnavailableError | Yes |
| 504 | timeout | The model did not answer in time. | TimeoutError (Python: OryvoxTimeoutError) | Yes |
| none | network failure | No HTTP response. | APIConnectionError (ConnectionError) | Yes |
| none | client timeout | TimeoutError / OryvoxTimeoutError | Yes |
Field validation on /cache/invalidate and /requests/{id}/feedback (e.g. a rating of 9)
answers 422 with {"message": "...", "errors": {"field": ["..."]}} instead of the error
object; the SDKs raise it as ValidationError with that message.
All SDK errors extend APIError, which extends OryvoxError, and expose status, type,
code and requestId (Node) / request_id (Python). When type and status disagree, the
SDKs choose the class by type. Test keys can trigger rate_limited, timeout,
provider_unavailable and invalid_response on demand (see
Getting started).
Handling errors
import Oryvox, { BudgetExceededError, InsufficientCreditsError, ValidationError } from '@oryvox/sdk';
try {
await client.responses.create({ model: 'oryvox-auto', input });
} catch (err) {
if (err instanceof InsufficientCreditsError) askForTopUp();
else if (err instanceof BudgetExceededError) notifyBilling(err.requestId);
else if (err instanceof ValidationError && err.type === 'blocked_by_policy') askUserToRemoveSecrets();
else throw err;
}from oryvox import BudgetExceededError, InsufficientCreditsError, ValidationError
try:
client.responses.create(model="oryvox-auto", input=text)
except InsufficientCreditsError:
ask_for_top_up()
except BudgetExceededError as e:
notify_billing(e.request_id)
except ValidationError as e:
if e.type == "context_too_long":
...Errors in streams
After a stream has started, errors arrive in the stream (data: {"error": ...} for chat,
event: error for responses). The SDKs raise them as the same classes, with status unset.
Retry policy
See SDKs > Retries. If you call the API without an SDK, retry only the
statuses marked "Yes" above, with exponential backoff, and reuse the same Idempotency-Key
(see Billing > Idempotency).