Skip to content

Error codes

Every error is JSON with an HTTP status, in one shape:

{
  "error": {
    "type": "invalid_request",
    "code": "invalid_request",
    "message": "The request body isn't a valid request: ...",
    "param": "input",
    "request_id": "req_0123456789abcdef01234567"
  }
}
FieldMeaning
typeThe kind of error. Branch on this
codeThe exact reason. Branch on this when you need to
messageA sentence for people; don't parse it
paramThe field or limit at fault, or null
request_idThe same as the x-request-id header. Quote it when you ask us for help

Some errors carry more fields beside these, such as pay, free_tier, balance_usd, or resets_at.

By status

StatustypeWhat to do
400invalid_requestFix the field named in param
401unauthorized (model routes), authentication (other routes)Send a valid key in Authorization: Bearer ...
402insufficient_balanceBuy credit, then retry: Buy credits
402payment_requiredPay the invoice in PAYMENT-REQUIRED, then retry: x402
402payment_refusedThe proof wasn't accepted; reason says why. Get a new invoice
403limit_reachedA limit set on the key was hit; param names it
403permissionThe key or login may not do this; often code is out_of_scope
404not_foundCheck the path, the id, or the model name
409conflictThe thing changed or already exists; read it again
429rate_limited (also too_many_requests)Wait for Retry-After seconds, then retry
500server_error, model_errorRetry; tell us if it keeps happening
502upstream_failedEvery provider we tried failed. Retry, or name another model
503no_routeNo provider meets the request's needs or price cap
503unavailableRetry later

Codes an agent meets often

StatuscodeWhyWhat to do
400invalid_proofSign-up challenge wrong, expired, or usedGet a new challenge
400invalid_nameAgent name not 1 to 64 bytesPick another name
401unauthenticatedNo key, or an unknown keyCheck Authorization
401signed_outA route that needs a login got an API key or nothingUse a login key (oa_sk_...)
402agent_free_requests_usedThe 20 free requests for today are usedBuy credit, or wait for resets_at
402agent_free_budget_usedThe free $0.005 for today is usedBuy credit, or wait
402agent_free_tier_fullFree use for all agents is used up todayBuy credit, or wait
402agent_payment_requiredThe request is outside the free tier (another model, images, too long)Buy credit, or change the request
402agent_balance_too_lowThe credit can't cover the request's most possible costBuy more credit
403out_of_scopeThe key lacks the scope this route needsUse a key with that scope: Scopes
403limit_reachedparam is limits.spend_cap, limits.requests_per_minute, limits.models, limits.expires_at, scopes.models, or scopes.actionsRaise the limit, or wait
404model_not_foundNo model by that nameGET /v1/models lists them
404not_an_agent/v1/agents/me with a key that isn't an agent'sUse the agent's own key
409idempotency_conflictSame Idempotency-Key, different bodyUse a new key for a new body
429agent_daily_limitAn agent's 20 decision or 500 other calls for today are usedWait for Retry-After, or hold $0.01 of credit
429signup_limitToo many sign-ups today from this address or networkWait for Retry-After
503signup_unavailableSign-up is pausedTry later

Errors after an answer has started

A streamed answer can't change its status once it has started. It ends with a response.failed (or error) event instead, and a full answer comes back with "status": "failed". Either way the error object has code and message.

event: response.failed
data: {"type":"response.failed","response":{"status":"failed","error":{"code":"upstream_failed","message":"..."}}}

Retrying

StatusRetry?
400, 401, 403, 404, 409No: change the request first
402After paying
429After Retry-After
500, 502, 503Yes, after a short wait. For decisions, send an Idempotency-Key

MCP errors

The MCP servers answer JSON-RPC errors: -32700 (not JSON), -32600 (not a request), -32601 (no such method), -32602 (no such tool, or bad arguments), and -32002 (no such resource). A tool's own failure is a normal result with "isError": true. See Connect to our MCP servers.