Errors
Is it Proxium or the vendor?
| You get | Origin | A vendor was called |
|---|---|---|
401, 400, 413, 415, 422 | Proxium refused the request | No |
429 with retry-after: 60 | A ceiling of the key or the app | No |
503 upstream_failed | Each model of the plan failed. The message gives the reason of the last attempt | Yes |
4xx upstream_refused | Each model of the plan refused the request. The status and the message are the first vendor's | Yes |
503 upstream_error, bad_upstream_response, video_failed | The vendor of a media call | Yes |
503 keystore_unavailable, limits_unavailable | Proxium cannot read a store | No |
A 503 has two origins: a vendor failure, or a store of Proxium that is down. The code tells which.
Every model of the plan can refuse the request, for example a video file that no model can read. Then your app gets the status and the message of the first vendor, with the code upstream_refused. When any model fails in another way, your app gets 503 upstream_failed. To see the answer of each vendor, open the call in Requests. See Debug a failed call.
Which 429 is this?
Proxium sends a 429 only for its own ceilings. The code and the message tell which one:
code | Message | Ceiling |
|---|---|---|
tenant_capped | key budget exceeded (<ceiling>), where <ceiling> is calls, cost, rpm or tpm | A ceiling of the virtual key |
source_capped | source budget exceeded for '<app>' (<ceiling>), where <ceiling> is calls or cost | A ceiling of the app in x-proxium-source |
Both carry retry-after: 60. On /v1/messages, the body has no code, so read the message.
A 429 of a vendor does not reach your app. Proxium calls a model at another vendor of the plan. With no other vendor in the plan, Proxium waits for the vendor's Retry-After, tries the model once more, then the next model.
The OpenAI error shape
Each route except /v1/messages sends an error in this shape. type and code hold the same value.
{
"error": {
"message": "invalid or revoked key",
"type": "invalid_key",
"code": "invalid_key"
}
}
The Anthropic error shape
/v1/messages sends each JSON error in the Anthropic shape. error.type comes from the status. The Proxium code is not in the body.
{
"type": "error",
"error": {
"type": "rate_limit_error",
"message": "key budget exceeded (calls)"
}
}
| Status | error.type |
|---|---|
| 400, 415, 422 | invalid_request_error |
| 401 | authentication_error |
| 402, 403 | permission_error |
| 404 | not_found_error |
| 413 | request_too_large |
| 429 | rate_limit_error |
| 529 | overloaded_error |
| Any other status | api_error |
Plain-text errors
Some errors come before Proxium reads the body. Their body is plain text.
| Status | Cause | Routes |
|---|---|---|
| 400 | The body is not valid JSON, or a path id is not a UUID | Each POST route except chat/completions and messages, and memory/* |
| 413 | The body is larger than the limit | All routes |
| 415 | The content type is not JSON | Each route except chat/completions and messages |
| 422 | The JSON does not match the body schema | memory/* |
Error codes
The Routes column leaves out /v1. "Inference" is chat/completions, messages, embeddings, moderations, rerank and responses. "Media" is images/generations, audio/speech and video/*.
Authentication
| Code | Status | Cause | Fix | Retry |
|---|---|---|---|---|
missing_key | 401 | The request has no virtual key | Send Authorization: Bearer <key>. On /v1/messages, x-api-key also works | No |
invalid_key | 401 | The key is not valid, revoked or expired | Make a new key on Endpoints or Keys | No |
keystore_unavailable | 503 | Proxium cannot read the key store | Wait, then retry | Yes |
limits_unavailable | 503 | Proxium cannot read the limits of the key | Wait, then retry | Yes |
Request
| Code | Status | Routes | Cause | Fix | Retry |
|---|---|---|---|---|---|
bad_json | 400 | chat/completions | The body is not a valid chat request | Fix the field that the message names | No |
unsupported_media_type | 415 | chat/completions | The content type is not JSON | Send Content-Type: application/json | No |
missing_model | 400 | embeddings, moderations, rerank, responses, images/generations, audio/speech | No model, or an empty one | Send a model | No |
bad_model | 400 | images/generations, video/generations | The model id has a character other than a letter, a digit, ., _, - or : | Send an id from GET /v1/models | No |
missing_operation | 400 | video/operations | No operation | Send the operation of video/generations | No |
missing_uri | 400 | video/download | No uri | Send the video_uri of the finished video | No |
forbidden_target | 400 | video/operations, video/download | The address is not a Google API host | Send the address that the video vendor gave | No |
invalid_memory_mode | 400 | Inference | x-proxium-memory is not write, recall or off | Fix the header | No |
invalid_memory_subject | 400 | chat/completions, messages, responses | x-proxium-memory-subject is too long, has a control character, or is not UTF-8 | Fix the header | No |
On /v1/messages, a missing max_tokens gets 400 invalid_request_error, with the message max_tokens: Field required. A model that is not a string gets the message model: Input should be a valid string. A missing model is not an error: the call uses auto, as on /v1/chat/completions.
Routing and vendors
| Code | Status | Routes | Cause | Fix | Retry |
|---|---|---|---|---|---|
no_route | 400 | Inference, media | No model of the route is open to this key. The message tells why | See the table below | No |
upstream_failed | 503 | Inference, media | Each attempt of the plan failed, or the vendor could not be reached | Read the attempts on Requests | Yes, with a wait |
upstream_refused | The first vendor's 4xx | Inference | Each model of the plan refused the request. The message is the first vendor's | Change the request as the message says | No |
upstream_error | 503 | Media | The vendor answered with an error. The message holds its status and body | Fix the request for that vendor, or the vendor key | No |
bad_upstream_response | 503 | images/generations, audio/speech, video/generations | Proxium cannot read the answer of the vendor | Retry. Then try a different model | Yes |
video_failed | 503 | video/operations | The vendor reports that the video failed | Start a new video | No |
bad_shape | 500 | Media | The vendor configuration names an unknown answer shape | Use a different vendor for this type | No |
On chat, Messages and the other JSON routes, Proxium answers no_route before it checks the ceilings, so the call uses no call slot. A model or vendor that your project retired never causes no_route: when every model of the plan is retired, Proxium calls them.
no_route message | Cause | Fix |
|---|---|---|
no models available for route | No vendor of the project serves this model or tier, and the catalog fill adds none, or your failover policy has the catalog fill off | Add a vendor on Providers, add a model to the tier, or turn the catalog fill on |
model not permitted for this key: … | The allow-list of the key refuses each model of the route | Use an allowed model, or a different key |
no providers configured | No vendor at all | Add a vendor on Providers |
no image provider configured, no tts provider configured, no video provider configured | No vendor of this type | Send a model id of a vendor of this type |
unknown image provider '…', unknown tts provider '…' | The vendor in model does not serve this type | Use an id from GET /v1/models |
If x-proxium-timeout-ms ends, the message of upstream_failed starts with client deadline exceeded.
Ceilings
| Code | Status | Cause | Fix | Retry |
|---|---|---|---|---|
tenant_capped | 429 | The key reached a ceiling: calls, cost, rpm or tpm | Wait | After retry-after |
source_capped | 429 | The app reached its ceiling: calls or cost | Wait, or raise the ceiling in Overview › Per-app burn | After retry-after |
Data protection
| Code | Status | Cause | Fix | Retry |
|---|---|---|---|---|
guardrail_blocked | 403 | A class of Data protection set to block matched the request. The message names the class and the place in the request, never the value | Remove the value in your app, or change the action of the class | No |
Memory
These codes come from the memory/* routes.
| Code | Status | Cause | Fix | Retry |
|---|---|---|---|---|
bad_request | 400 | A field is missing or wrong, or the text is empty or too long | Fix the field that the message names | No |
forbidden | 403 | The key sent pinned: true, or a person wrote the memory that the key tried to change | Leave out pinned. Ask a person to change the memory | No |
not_found | 404 | No such conversation or live memory | Check the id | No |
memory_off | 409 | Memory is off for the project | Turn memory on in Settings | No |
query_failed | 500 | A database query failed | Wait, then retry | Yes |
Errors in a stream
| When the failure comes | Your app gets |
|---|---|
| Before the first piece | A normal error status and body, as above. No stream opens |
| After the first piece, OpenAI format | The stream stops. No data: [DONE] follows |
| After the first piece, Anthropic format | An error event, then the stream ends |
Proxium cannot move a stream to another model after the first piece. It does not cache a stream that stopped.
Codes that proxium.tech does not send today
| Code | Status | When a deployment sends it |
|---|---|---|
subscription_required | 402 | The project may not send calls. proxium.tech is in open beta |
budget_unavailable | 503 | The budget store is down and the deployment refuses calls. proxium.tech lets the call through |