Error catalogue
Every error the public API emits, the shape of the body, and what to do about each.
We use HTTP status codes for the broad category and a stable error.code
(or detail) string for the specific reason. Codes are stable for the
same condition.
Envelopes
Most errors return one of two envelopes.
Plain detail (auth failures, validation):
{ "detail": "invalid_api_key" }
Structured error (billing, rate-limit, request-size):
{
"error": {
"type": "billing_error",
"code": "spend_cap_exceeded",
"message": "...",
"docs_url": "https://docs.olava.dev/billing/spend_cap_exceeded",
"resolution_url": "https://console.olava.dev/billing",
"portal_url": "https://console.olava.dev/billing"
}
}
Branch on error.code (or the equivalent error.reason alias) — do
not branch on error.message, which is human copy and may change.
4xx
400 Bad Request
detail / code | Cause |
|---|---|
invalid_json_body | Body could not be parsed as JSON. |
body_must_be_object | Body parsed but isn't a JSON object. |
401 Unauthorized
detail | Cause |
|---|---|
missing_bearer_token | No Authorization: Bearer ... header. |
invalid_api_key | Key not found, malformed, or revoked. |
402 Payment Required
All carry the structured error envelope. The code (and reason alias)
is one of:
| Code | Cause | Recovery |
|---|---|---|
onboarding_incomplete | No spend cap set, or onboarding not finished. | Finish onboarding in the console. |
spend_cap_exceeded | Call would exceed monthly cap. | Raise the cap from the console, or wait for the period rollover. Retry-After header is set. |
payment_failed | Last invoice failed to charge. | Update payment method via the console's Manage billing flow. |
subscription_canceled | Subscription has been cancelled. | Resubscribe via the console. |
413 Payload Too Large
code | Cause |
|---|---|
input_too_large | Chat input above 32,768 tokens. |
| (no code, plain 413) | Request body above 32 MB. |
429 Too Many Requests
Always carries Retry-After (seconds).
| Code | Cause |
|---|---|
api_key_rate_limited | Per-key request limit exhausted. Honor Retry-After. |
5xx
503 Service Unavailable
The service is temporarily unavailable. The response carries a
Retry-After header; back off and retry.
Streaming errors
For POST /v1/chat/completions with stream: true, errors after the
response has started are delivered as SSE event: error chunks rather
than HTTP status codes:
event: error
data: {"code":"spend_cap_exceeded","message":"...","docs_url":"..."}
The stream closes immediately after. Chunks emitted before the error are still billable.
If the service hits an internal error after streaming has started:
data: {"error":"service_unavailable","status":500}
data: [DONE]
In that case you are not billed — only fully-completed calls produce a usage record.