title: Errors description: Every error LIBRA can return, what causes it, and what to do about it.
Errors
Every error uses the same shape, so you can handle them uniformly:
{
"error": {
"message": "This API key has expired.",
"request_id": "req_2ae80f15bd6e",
"type": "key_expired"
}
}
Branch on type, not on message. The message wording may improve over time; the
type is stable. Always log request_id: it is the fastest way for support to find
your exact request.
Your key or your account
| Type | HTTP | What happened | What to do |
|---|---|---|---|
invalid_api_key |
401 | The key does not exist, or the Authorization header is malformed. |
Check the header reads Authorization: Bearer libra_sk_.... Keys are shown once at creation; create a new one if it is lost. |
key_disabled |
401 | The key was switched off in the console. | Re-enable it under API keys, or use another key. |
key_expired |
401 | The key passed its expiry date. | Create a new key, or clear the expiry on this one. |
org_suspended |
403 | The organization is suspended, so every key stops working. | Contact sales. Nothing in the console will restore access by itself. |
Credit and limits
All four mean a budget was reached. They are separate types so you can tell which budget without parsing prose.
| Type | HTTP | What happened | What to do |
|---|---|---|---|
insufficient_credits |
402 | The organization balance is zero or below. | Top up. Balance is visible under Credits. |
workspace_budget_reached |
402 | The workspace hit its credit limit for the period. | Raise the workspace limit, or wait for the period to reset. |
key_budget_reached |
402 | This key hit its own credit limit. | Raise the key limit, or use a different key. |
rate_limited |
429 | Too many requests too quickly. | Back off and retry. Honour Retry-After when present. |
Note that credit checks run before the request is sent, so a key with a budget smaller than the cost of one request is refused immediately rather than part way through.
The model you asked for
| Type | HTTP | What happened | What to do |
|---|---|---|---|
model_not_found |
404 | No such model or alias, or it is disabled platform-wide. | Call GET /v1/models for the current list. |
model_not_allowed |
403 | The model exists, but this key's guardrails do not permit it. | Pick a model from the key's allowed list, or change the guardrail. |
provider_blocked |
403 | The model exists and is allowed, but the key's guardrails block every provider that could serve it. | Unblock a provider in the guardrail, or choose a model served elsewhere. |
no_eligible_provider |
400 | Nothing can serve this model right now: every provider in its chain is down or switched off. | This is an outage, not a configuration problem. Retry shortly. |
provider_blocked and no_eligible_provider are deliberately different. The first
is your policy refusing the request; the second is a real outage. If you see the
first, look at your guardrails, not at our status page.
Your request
| Type | HTTP | What happened | What to do |
|---|---|---|---|
invalid_request |
400 | The body is not valid JSON. | Check for truncation or a trailing comma. |
request_too_large |
413 | The body exceeds 4 MB. | Send less context, or split the work across requests. |
unsupported_parameter |
400 | The body carries a parameter this model cannot handle. | Almost always tools sent to a model without tool support. Switch to a tool-capable model such as asix-deepseek-v4/deepseek-v4-flash, or the libra/smart alias. |
method_not_allowed |
405 | Wrong HTTP method for this path. | Chat completions is POST; the model list is GET. |
unknown_endpoint |
404 | No such path under /v1. |
Check the URL. The base URL must end in /v1. |
not_implemented |
501 | A reserved endpoint that is planned but not built, such as /v1/agents. |
Nothing to do; it will start working when the feature ships. |
The provider or LIBRA itself
| Type | HTTP | What happened | What to do |
|---|---|---|---|
upstream_rejected |
400 | The provider refused the request, usually a malformed or unsupported field. | Check your parameters against the provider's limits. |
upstream_error |
502 | The provider returned an error. | Retry. If it persists, the provider is having trouble. |
upstream_timeout |
504 | The provider did not answer in time, 180 s. | Retry, and consider a smaller request. |
all_providers_failed |
502 | Every provider in the chain was tried and all failed. | Retry with backoff. This is an outage on the provider side. |
gateway_unavailable |
503 | LIBRA cannot reach its own gateway. | Retry with backoff. Check /healthz. |
Retrying safely
Retry these, with exponential backoff: rate_limited, upstream_error,
upstream_timeout, all_providers_failed, gateway_unavailable,
no_eligible_provider.
Do not retry these; they will fail identically until something changes:
invalid_api_key, key_disabled, key_expired, org_suspended,
insufficient_credits, workspace_budget_reached, key_budget_reached,
model_not_found, model_not_allowed, provider_blocked, invalid_request,
request_too_large, unsupported_parameter, method_not_allowed,
unknown_endpoint, not_implemented.
Checking whether it is us
GET /healthz needs no key and reports whether the gateway has providers loaded:
{ "status": "ok", "gateway_providers": 2 }
A status of degraded with gateway_providers: 0 means LIBRA is up but cannot
route anything, and every chat request will fail until it recovers.