Errors
The shapes an error takes in the CLI, REST API, MCP tools and failed runs, plus a lookup table for every code and its fix.
Every error carries a stable code you can match on, a plain message, and, where there is one
thing to do, a fix. Quote the requestId (or a run’s runId) when you ask for help.
There are four places an error can show up, and each has its own shape.
CLI stderr
On a terminal, looot prints one line, then the fix:
The workspace balance is too low to reserve this run's estimated cost. (request req_...)
Fix: Add credits at https://looot.ai/usage?top_up=1
Piped, or with --format json or --format jsonl, it prints one JSON object on stderr and exits
with code 1:
{
"code": "insufficient_balance",
"message": "The workspace balance is too low to reserve this run's estimated cost.",
"retryable": false,
"status": 402,
"requestId": "req_...",
"fix": "Add credits at https://looot.ai/usage?top_up=1",
"error": { "code": "insufficient_balance", "message": "..." }
}
| Field | Meaning |
|---|---|
code |
Stable, snake_case. The gateway’s own code when the gateway answered. |
message |
One sentence, never a stack trace or an HTML page. |
retryable |
true when the exact same command may succeed on a retry (a dropped connection, a timeout, a 429, a 5xx). false when the request itself has to change. |
status |
The HTTP status, when the gateway answered. |
requestId |
The gateway’s id for the request. |
fix |
What to do next. |
retryCommand |
looot run only: the exact command to retry with the same idempotency key. |
Nothing on stdout mixes with an error: stdout carries only a command’s result. Ctrl+C prints
Cancelled. and exits with code 130. See CLI command reference and
CLI errors for the local, network and file errors that never reach the
gateway.
REST errors
GET/POST/etc against https://api.looot.ai answer with an HTTP status and a JSON body:
{ "error": { "code": "idempotency_conflict", "message": "...", "requestId": "req_..." } }
Some routes add fields next to error. POST /v1/runs at 402 adds balanceMicros,
estimatedCostMicros and a topUp object with a checkout link; POST /v1/runs at 429 adds
inflight, limit and retryAfterSeconds. See REST errors.
A 201 from POST /v1/runs can still carry "status": "failed" or "status": "blocked", for
example when the input fails the endpoint’s own schema. Check status and error on the run
body, never the HTTP status code alone.
MCP tool errors
A failed tool call returns isError: true, with the same object in both content[0].text (as
compact JSON) and structuredContent.data:
{
"code": "idempotency_conflict",
"message": "This idempotencyKey was already used with a different body. Reuse the exact same body to replay the original, or pick a new idempotencyKey for a new request.",
"retryable": false,
"requestId": "req_...",
"error": "idempotency_conflict"
}
message always says what to do next. error repeats code as a plain string, kept for a
caller written against the older { error: "<code>" } shape. Arguments that don’t match a tool’s
schema come back as validation_error naming the field. Anything unexpected comes back as
internal_error with a requestId to report. See MCP errors.
Failed runs
When a run itself fails, the run record carries an error object, whatever surface fetched it
(runs_get, runs_list, the inline result of run, or GET /v1/runs/{id}):
{
"code": "provider_error",
"providerStatus": 502,
"message": "The provider returned an error response.",
"requestId": "req_...",
"whoseError": "provider",
"retryable": true,
"retryHint": "Retry the run; if it keeps failing, the provider itself is rejecting or down."
}
whoseError says whose side the problem is on: provider, gateway or customer (you). A
failed run settles at $0 (or the provider’s evidenced partial cost) and any remaining hold is
released. A job:<id> run that never called a provider gets its own two codes,
route_capped and route_no_fit; see Job refusals for those and for the
result.code values a job: run’s failed body carries. See Run errors for
the full list.
Every code
| Code | Where | Section | What fixes it |
|---|---|---|---|
validation_error |
REST 400, MCP, run, CLI | REST | inspect |
unauthorized |
REST 401, CLI | REST | Sign in |
token_revoked |
REST 401, CLI | REST | Sign in |
forbidden |
REST 403, MCP, CLI | REST | Access |
not_found |
REST 404, MCP | REST | runs_list |
route_not_found |
REST 404 | REST | API reference |
method_not_allowed |
REST 405 | REST | API reference |
idempotency_conflict |
REST 409, MCP, CLI | REST | Idempotency |
rows_mode_unsupported |
REST 422, MCP | REST | inspect |
too_many_inflight_runs |
REST 429, MCP, CLI | REST | Idempotency |
rate_limit_exceeded |
REST 429, CLI | REST | Wait and retry |
runs_cursor_invalid |
REST 400, MCP | REST | runs_list |
unknown_category |
REST 404, MCP, CLI | REST | catalog_overview |
unknown_platform |
REST 404, MCP | REST | catalog_overview |
internal_error |
REST 500, MCP | REST | Support |
catalog_loading |
REST 503, MCP, CLI | REST | Wait and retry |
storage_busy |
REST 503, MCP, CLI | REST | Idempotency |
storage_uncertain |
REST 503 | REST | Idempotency |
billing_unavailable |
REST 503 | REST | Support |
runtime_bridge_timeout |
REST 503 | REST | Wait and retry |
insufficient_balance |
REST 402, run, MCP, CLI | REST | Top up |
provider_error |
run, CLI | Run errors | Fallback |
provider_reported_error |
run, CLI | Run errors | Fallback |
timeout |
run, CLI | Run errors | Fallback |
rate_limited |
run | Run errors | Idempotency |
auth_error |
run | Run errors | Bring your own provider key |
invalid_response |
run | Run errors | Support |
unsupported_response_type |
run | Run errors | Support |
response_too_large |
run | Run errors | Fallback |
redirect_blocked |
run | Run errors | Fallback |
output_mapping_error |
run | Run errors | run |
endpoint_not_found |
run, CLI | Run errors | search |
eligibility_blocked |
run | Run errors | Access |
activation_blocked |
run | Run errors | search |
credential_denied |
run | Run errors | Bring your own provider key |
platform_key_missing |
run | Run errors | Bring your own provider key |
platform_auth_incompatible |
run | Run errors | Bring your own provider key |
credential_placement_unsupported |
run | Run errors | Support |
budget_exceeded |
run | Run errors | Cost cap |
provider_disabled |
run, CLI | Run errors | search |
provider_draining |
run | Run errors | Fallback |
connection_not_found |
run | Run errors | Access |
connection_invalid |
run | Run errors | Bring your own provider key |
provider_http_error |
run | Run errors | Fallback |
fetch_failed |
run | Run errors | Fallback |
connection_unusable |
run | Run errors | Bring your own provider key |
contract_invalid |
run | Run errors | Support |
route_denied |
run | Run errors | Support |
no_route_candidate |
run | Run errors | Fallback |
capacity_exhausted |
run | Run errors | Wait and retry |
cancelled_before_dispatch |
run | Run errors | runs_cancel |
cancellation_requested_after_dispatch |
run | Run errors | runs_evidence |
runtime_store_replaced_before_dispatch |
run | Run errors | Idempotency |
route_capped |
run | Job refusals | Cost cap |
route_no_fit |
run | Job refusals | Fallback |
unknown_job |
run result | Job refusals | search |
no_supply_for_job |
run result, search | Job refusals | capability_request |
needs_input |
run result | Job refusals | Job inputs |
no_runnable_provider |
run result | Job refusals | Bring your own provider key |
invalid_input |
run result | Job refusals | Job inputs |
unknown_tool |
MCP | MCP errors | MCP tools |
workflow_not_found |
MCP | MCP errors | run |
top_up_amount_out_of_range |
MCP, run | MCP errors | Top up |
top_up_unavailable |
MCP, run | MCP errors | Top up |
Local CLI codes (token_required, network_error, invalid_input_json, …) |
CLI only | CLI errors | CLI errors |
See Money: free calls and failures for how a failed or refused run is charged.