Skip to main content
The API returns standard HTTP status codes with OpenAI-style error bodies, so most existing OpenAI-compatible client libraries can parse them without changes. Every error response has the same shape:
string
A human-readable description of the problem. Safe to log and surface to developers, but do not parse it programmatically; parse type and code instead.
string
The high-level error category. One of invalid_request_error, insufficient_quota, permission_error, rate_limit_error, api_error, or upstream_error.
string
The specific machine-readable error: invalid_api_key, insufficient_balance, upgrade_required, insufficient_scope, insufficient_permissions, model_not_found, dedicated_endpoint_not_found, unknown_provider, and on the management API also not_found, precondition_failed, logging_disabled and a few endpoint-specific codes. Branch on this value in your error handling.
string
Present only on insufficient_scope: the scope the call needed.

Status codes

Error codes

The type and code fields pinpoint the exact failure. Use the table to map a code to its category, HTTP status, and remedy.
The key is missing, malformed, or revoked. Keys are sent as Authorization: Bearer <key>. Confirm the header is present and the key is active in your workspace. Rotating a key immediately invalidates the old one, so deployments still holding a stale key will see this error.
Before a request runs, errorbar places a hold on your wallet for the request’s worst-case cost, enough to cover the maximum tokens it could produce. If the wallet can’t cover that hold, the request is rejected with 402 before any provider is called. You’re never charged for a request that returns 402. Add funds or turn on auto-reload to avoid interruptions. Capping max_tokens also lowers the hold, since the worst case shrinks.
The request was well-formed and the key was allowed to make it, but the workspace’s plan doesn’t include acting on it. The management API raises this when a PUT /v1/aliases sets a canary percentage above 0 or gate_mode: "auto" on a plan without partial rollouts or gate enforcement, and when POST /v1/dedicated creates an endpoint on a plan without dedicated capacity. The message always starts with Upgrade to <Plan> and names the plan that includes the action; nothing is charged. Not retryable: change the plan or the request.
The key exists and is valid, but it was minted without the scope this call needs. The body’s required_scope names it (evals:write, aliases:write, or platform:write; reads are never refused this way, since every scoped key can read). Mint a key with that scope from the dashboard’s API keys page, or use a key created with full access. Keys minted before scopes existed are never refused this way. See Key scopes.
A key acts as the user who minted it. Endpoints that spend money or redirect traffic require that user to be a workspace owner or admin; this is the refusal when they aren’t. Mint the key from an owner/admin account. See Key permissions and roles.
The model you requested isn’t in the priced catalog: either the id is misspelled or the model isn’t offered. This is a deliberate 404: errorbar refuses to run a model it can’t price so you’re never billed for an unpriced model. Call /v1/models to list valid ids.
You addressed a dedicated endpoint as dedicated/<routing-key>, but that routing key either isn’t owned by your workspace or has been deleted. Check the routing key on the endpoint’s page in the dashboard, and confirm the endpoint still exists. See Dedicated endpoints.
You used a provider prefix that has no configured key. Verify the provider prefix is spelled correctly and that a key for that provider is configured for your workspace.
A transient error reaching the model provider. Retry with exponential backoff. The message includes a request id reference; quote it if you contact support.

Retrying safely

Retry 429, 408, and 502 responses with exponential backoff and jitter.
Completions are safe to retry: you’re only billed for tokens actually produced. A retried request that never returned tokens costs nothing.
For a 502, the message includes a request id reference. Quote that reference if you contact support so the request can be traced.
Don’t blindly retry 4xx errors other than 408 and 429. A 400, 401, 402, 403, or 404 means the request, the key, or the plan needs to change; retrying it unchanged will fail the same way every time.

Python

This helper retries only the transient statuses and backs off exponentially with jitter:

curl

curl --retry with backoff covers the transient cases for simple scripts:

Inspecting errors after the fact

Every failed request appears in the dashboard’s request log, and the Errors by cause breakdown groups failures by category (rate limits, timeouts, upstream errors). See Observability to diagnose patterns across many requests rather than one at a time.