Errors
Errors are returned as a JSON envelope with a machine-readable kind and a
human-readable message:
{ "error": { "kind": "not_found", "message": "Run not found" } }Branch on kind (stable); show message to humans (may change).
Error kinds
Section titled “Error kinds”kind |
HTTP | When |
|---|---|---|
validation |
400 | The request body, params, or query failed validation. |
unauthorized |
401 | Missing or invalid API key. |
forbidden |
403 | Authenticated, but not allowed (e.g. wrong organization). |
not_found |
404 | The resource doesn’t exist (or isn’t in your tenant). |
conflict |
409 | The request conflicts with current state. |
rate_limited |
429 | Too many requests — back off and retry. |
internal |
500 | An unexpected server error. |
unavailable |
503 | A dependency was temporarily unreachable — retry. |
rate_limited and unavailable are the two transient kinds; every other
kind is a decision about your request and will answer the same way again.
An input we do not understand is refused, never ignored
Section titled “An input we do not understand is refused, never ignored”A field or query parameter an endpoint does not declare is a 400 naming it,
on both halves of a request:
{ "error": { "kind": "validation", "message": "filter: unknown query parameter for GET /v1/brains/:handle/search. It accepts: q, mode, limit, consumerId." }}This matters most where a parameter would have NARROWED an answer. Dropping an
unrecognized filter= and answering 200 returns a confident, well-formed
ranking over the whole Brain to a question that asked for one slice of it —
and nothing in the response says so. Refusing it is the only answer you can
act on, and it is why a client generated against an older shape of a preview
endpoint fails loudly at the parameter it should stop sending rather than
quietly reading something else.
Correlating a request
Section titled “Correlating a request”Every /v1/* response — success or error — carries an x-request-id header.
Log it alongside the request you made; when you report a failed call, include
it so the failure can be found on our side without you having to attach a
full HTTP transcript. It has no fixed format: usually a UUID, but on some
requests it is Cloudflare’s own cf-ray value, echoed as-is rather than
minting a second id for the same request.
curl -sD - https://api.nicia.ai/v1/brains \ -H "authorization: Bearer $NICIA_KEY" \ | grep -i x-request-idRetrying
Section titled “Retrying”429 and 5xx are safe to retry with exponential backoff. When retrying
POST /v1/runs, send an Idempotency-Key so a retry
never creates a duplicate run. 4xx errors other than 429 indicate a problem
with the request itself — fix it rather than retrying.