code, not on the HTTP status and not on the message. The status
is what a proxy needs; the code is what your integration needs. Messages are
written for people and may be reworded.
request_id is also on the x-request-id header. Quote it when you ask us
about a call — it is how we find that exact request in our logs.
Every /v1 response carries x-request-id, not only the failures — a 200,
a 202, an SSE stream. The calls worth asking about are often the ones that
succeeded and did something surprising, and those need a handle too. Log the
header next to whatever your integration records about the call; it costs
nothing until the day it is the only thing that helps.
The codes
A401 also carries WWW-Authenticate: Bearer realm="gobare", error="…" —
the standard challenge, so an HTTP client learns the scheme without being
configured for it.
The Retry column is also on the wire. Every code marked retryable carries
a Retry-After header; the ones marked no carry none, and the absence is the
signal — project_limit_exceeded is a 429 and provider_unauthorized is a 502,
and neither is a wait. A client that honours Retry-After and gives up without
one is doing the right thing on every row below without knowing any of them.
The numbers are a floor on politeness rather than a prediction. Where we can
compute the real wait — the rate limiter, the stream ceiling — we send that
instead.
Refusals worth recognising
Severalinvalid_request refusals exist specifically so a value is never
accepted and then ignored. Each names what to do:
An
environment.profiles id belonging to another organization answers
not_found, not permission_denied — an id cannot be probed for existence.
The three 429s
They share a status and recover differently, which is exactly why the code matters more than the status:rate_limit_exceeded— you are asking too fast.Retry-Aftersays how long to wait, and honouring it works. See limits.md.queue_full— this session is saturated. Wait for its turns to drain, or use another session.project_limit_exceeded— you are at the ceiling for concurrent sessions. Retrying never succeeds. Delete something or talk to us.
Internal errors
An unexpected failure is reported asinternal_error with a fixed message.
Internal errors routinely carry file paths, SQL and provider responses, and none
of that belongs in an external response. The real message is in our logs,
findable by the request_id you were handed.
If you see one, it is worth reporting.
Errors from outside the API
/v1 always answers JSON in this envelope, including 404 for an unknown path
— so a JSON parse failure means you did not reach /v1 at all. Check the host
and the /v1 prefix.
A 413 from an intermediate proxy is likewise not us; our own body ceiling
answers invalid_request with 400.
Next
- input — what each input event accepts, and when each refusal happens
- troubleshooting — a symptom rather than a code
- limits — the ceilings behind the 429s