Every error code the API returns, by family, with what to do about each.
Every error carries a machine-readable code from the closed set below. Branch on code, never on detail. The response shape and retry rules are in Errors.
Each code's type URL is https://dashboard.sproutsdata.ai/errors/<slug>, where the slug is the code with . and _ replaced by -. It redirects to that code's entry on this page.
422: field validation failed — a bad value, an unknown parameter, a missing query/filters, an over-cap batch, or the retrieval engine rejected the query. extra.errors[] names the fields, and each entry's msg is written to be shown to a developer. 400:POST /v1/agents/runs without an Idempotency-Key, or with one longer than 255 characters. 404: an agent run id that doesn't exist or belongs to another workspace, or an unknown path (see the http-<status> fallback)
Fix the request. Do not retry unchanged
request.too_large
413
Reserved: the request body exceeds the size cap
Send a smaller body
request.unsupported
415
Wrong content type — e.g. a form-encoded body on a session POST
Send Content-Type: application/json
The validation payload shape:
{ "code": "request.invalid", "detail": "One or more fields failed validation.", "extra": { "errors": [ { "type": "less_than_equal", "loc": ["body", "limit"], "msg": "Input should be less than or equal to 100", "input": 500, "ctx": { "le": 100 } } ] }}
Its own namespace rather than request.invalid, because the request was valid: you named something the corpus holds more than one of. A client should branch on that differently than on a malformed body — the same reasoning that keeps auth.* separate from request.*.
Code
Status
When you see it
What to do
relationship.anchor_ambiguous
422
A company named by name — on any /v1/relationships* route, including inside a sentence sent to /ask — matched more than one record
Read extra.anchor (what you sent) and extra.candidates (what it could have been) and let someone pick. Anchoring by domain avoids it entirely
The feedback routes. Reporting a bad result is free, so neither of these is ever a billing question.
Code
Status
When you see it
What to do
feedback.subject_not_found
404
The request_id or run_id you reported against is unknown, outside the history window, or not yours — deliberately one code for all three, so it is not an existence oracle for another tenant's runs
Report against a meta.request_id from your own recent response. Only the first page of a paginated call is recorded
feedback.unavailable
503
The feedback store could not be reached. Nothing was filed
Retry shortly. Never surface this as "your report was rejected"
The saved lists routes. Lists are free, so none of these is a billing question.
Code
Status
When you see it
What to do
lists.not_found
404
No such list in this workspace. A missing list, a deleted one and another workspace's get the same answer on purpose
Take ids from a fresh list of your lists; don't retry
lists.item_cap_reached
409
Saving these items would take a free workspace past its saved-items cap, which counts items across all its lists. The cap is a platform setting; when none is set there is no cap. extra carries cap, saved and adding. Nothing was saved
Save fewer items, remove some, or upgrade the workspace
lists.unavailable
503
Saved lists couldn't be reached. Nothing was changed
Reserved: no route sends either code today. A reused Idempotency-Key never produces an error:
On the billed routes that honour it, the same key with the same body on the same UTC day is recognised as a retry. The same key with a different body silently starts a new request.
On POST /v1/agents/runs, the key is required, and a reused key returns the original run's handle with 200 instead of 202, whatever the body says. It starts and charges nothing. Run keys never expire and are scoped to your workspace.
Code
Status
When you see it
What to do
idempotency.in_flight
409
Reserved: a request with the same idempotency key is still executing
Wait for the original to finish
idempotency.fingerprint_mismatch
409
Reserved: an idempotency key was reused with a different request body
Infrastructure protection — always 429, never a billing question. There is no per-key request-rate limit on the REST API today; the codes below are the limits that exist. Honour Retry-After whenever it is present.
Code
Status
When you see it
What to do
quota.burst_exceeded
429
Too many requests in a short window, with Retry-After. Sent by the playground's session throttles (30 requests a minute and 500 a day), the sign-in throttle, and the MCP server (60 calls a minute per credential)
Wait Retry-After seconds. If you're automating through the playground, use an API key instead
quota.daily_exhausted
429
Reserved: never sent today
Treat like quota.burst_exceeded
quota.monthly_exhausted
429
Reserved: never sent today
Treat like quota.burst_exceeded
quota.concurrency_exceeded
429
Sent only by POST /v1/agents/runs: more than 5 runs are being started at the same moment by one credential. Carries Retry-After: 30
Wait Retry-After seconds, then retry with the same Idempotency-Key
quota.entity_ceiling
429
Sent only by POST /v1/agents/runs: the credential has been shown 5,000,000 distinct records (the default ceiling) in the last 30 days, through searches and run results. extra carries seen and limit
Commercial — a different family from quota.* by design, and the two are never conflated. A 402 is fixed by buying; a 429 is fixed by waiting. See Credits & usage.
Code
Status
When you see it
What to do
credits.insufficient
402
The data-platform allocation cannot fund what this call delivered, so its results are not returned. extra carries available and required (credits, to three decimals), action_type (and sometimes unrestricted_not_usable)
Buy or transfer credits. Never retry — no amount of waiting helps
credits.unavailable
503
The billing system could not be reached, or did not confirm the charge in time, so the request may have been charged. This is the one error that can cost credits
Retry shortly with the same Idempotency-Key, so rows already paid for aren't charged twice. Check meta.credits_charged on the retry
credits.unknown_action
500
Our misconfiguration: an action has no pricing row. Deliberately a 500 and never a free pass
Report it with the request_id; nothing was charged
Buying credits, on the dashboard's billing routes. Separate from credits.* because the failures are the buyer's to fix rather than a spend outcome:
a 402 credits.insufficient means "you have none";
a 402 payment.declined means "the card was refused", and sending it to a top-up screen is a dead end.
Almost all of these are reachable only with a signed-in dashboard session. The exception is payment.topup_not_found, which comes from the two top-up link routes that any credential can call. The rest are listed because code is a closed set and this page is the whole of it, as are the dashboard-only codes below.
Code
Status
When you see it
What to do
payment.invalid_amount
422
The amount is not purchasable
Offer a valid amount; detail says what was wrong
payment.declined
402
The bank said no. detail is the card network's own message, passed through verbatim
Show detail and offer another card. Never route this to a "buy credits" screen
payment.no_method
409
No card on file — a missing prerequisite, not a failed purchase
Send the user to add a payment method first
payment.forbidden
403
The signed-in user lacks billing permission for the organisation
Point them at an owner; re-authenticating will not help
payment.unavailable
503
The payment service could not be reached. Nothing was charged
Retry after Retry-After
payment.topup_not_found
404
The top-up id is unknown, has expired (links last 15 minutes), or belongs to another workspace. The three cases get one answer on purpose
Start a new top-up with POST /v1/billing/top-up/intents
The retrieval engine or the agent engine failed. A metered call is charged only once its response is ready, so neither of these is charged. On search and lookup routes both carry Retry-After: 5.
Code
Status
When you see it
What to do
upstream.unavailable
503, 502
503: the retrieval engine or the agent engine is unreachable. 502: on the agent-run routes only, the agent engine answered with an error. Not charged
Retry after Retry-After, or shortly when there is none. Retrying a run start with the same Idempotency-Key is safe
upstream.timeout
504
The retrieval engine did not answer in time. Not charged
The run_id sent to GET /v1/usage/history/{run_id} is unknown, past the 90-day retention, or belongs to another credential — deliberately indistinguishable
The server is the limitation, not your request: a category whose index isn't wired in this environment, or a capability that isn't built yet. detail says which capability
Disable the feature; don't retry. Distinct from request.unsupported, which means you asked for something invalid
internal
500
An unexpected error on our side. No stack trace ever leaks; the details are logged against request_id