Errors
When a request fails, the API returns an HTTP status and a JSON body with a stable code. Branch on code, never on message: messages are written for humans and can change.
Error shape
Error response
{
"error": {
"code": "BUDGET_EXCEEDED",
"message": "Service pixora has spent $2.0004/$2 today (2026-09-12 UTC); the budget resets in 3600s",
"requestId": "<upstream request id, when a model was reached>",
"model": "google.gemma-3-12b-it"
}
}
requestId and model are present when the error came from a model call. Include requestId when you report a problem.
A body of the form {"message": "..."} with no error object did not come from the API: it came from API Gateway before your request reached it. See Gateway errors.
Request and account errors
| Status | Code | Meaning | Retry |
|---|---|---|---|
| 400 | INVALID | The body failed validation — an unknown field, a missing maxTokens, a bad type. | No |
| 400 | USER_REQUIRED | Your service meters credits and requires userId on every call. | No |
| 400 | MODEL_NOT_PRICED | A metered call named a model with no catalog price, so its cost can't be charged. | No |
| 401 | UNAUTHORIZED | The key exists but isn't llm::<role>::<app>::<email> with customerId <app>. | No |
| 403 | NO_SERVICE | The key's service isn't registered. | No |
| 403 | DISABLED | Your service has been disabled. | No |
| 403 | MODEL_NOT_ALLOWED | Your service is restricted to a list of models and this isn't one of them. | No |
| 402 | INSUFFICIENT_CREDITS | The user's wallet can't cover the most this call could cost. Nothing was charged. | After a top-up or the monthly reset |
| 404 | NOT_FOUND | No such route or method. | No |
| 409 | CREDITS_NOT_ENABLED | GET /v1/credits/{userId} on a service that doesn't meter credits. | No |
| 429 | BUDGET_EXCEEDED | Your service reached its daily budget. | After midnight UTC |
| 501 | NOT_IMPLEMENTED | The route exists but isn't available yet (streaming). | No |
| 500 | INTERNAL | An unexpected error in the API. | Yes, with backoff |
| 503 | WALLET_BUSY | The user's wallet kept changing under concurrent calls. | Yes, with backoff |
Model errors
These come from the model call. Throttling, server errors and network failures have already been retried inside the API before you see them.
| Status | Code | Meaning | Retry |
|---|---|---|---|
| 400 | BAD_REQUEST | The model rejected the request — an unsupported parameter or schema. | No |
| 403 | AUTH | The model isn't enabled for the account — see unavailable models. | No |
| 404 | NOT_FOUND | The model doesn't exist in this region. | No |
| 422 | TRUNCATED | Output stopped at maxTokens before it was complete. Raise maxTokens; don't edit the prompt. | With a larger maxTokens |
| 429 | THROTTLED | The model's tokens-per-minute quota is still exhausted after retries. | Yes, later |
| 499 | ABORTED | The call was cancelled. | — |
| 502 | BAD_OUTPUT | The model broke the contract: output wasn't valid JSON, or called the wrong tool. | Maybe once |
| 502 | SERVER | Mantle kept failing after retries. | Yes, later |
| 504 | TIMEOUT | The model call exceeded 26 seconds. | With less output |
Gateway errors
API Gateway answers these itself, so the body is {"message": "..."} rather than an error object.
| Status | Body | Meaning |
|---|---|---|
| 403 | {"message":"Forbidden"} | Missing or unknown x-api-key. |
| 429 | {"message":"Too Many Requests"} | Over your plan's request rate. Retry after a backoff. |
| 429 | {"message":"Limit Exceeded"} | Over your plan's daily request quota, until midnight UTC. |
| 504 | {"message":"Endpoint request timed out"} | The request ran past API Gateway's 29-second limit. |
The SDK retries the gateway's 429 and 5xx responses automatically, and never retries BUDGET_EXCEEDED or INSUFFICIENT_CREDITS. It also raises three codes of its own when no usable response arrives — TIMEOUT, NETWORK and BAD_RESPONSE — described on the SDK page.