Connect by JBRH Open Connect

API error shapes

Errors come back as {"error": {"code": …, "message": …}} with a matching HTTP status. Two codes exist today — not_found at 404 and rate_limited at 429. A parameter outside its documented bounds is rejected earlier, by request validation, and that one response uses the framework's own shape rather than this envelope.

Status
Available What this means
Audience
developer
Last verified
Product version
6.3.2

The envelope#

{"error": {"code": "not_found",
           "message": "No public page for '/docs/nope/'. Search first: /api/public/docs/search?q=…"}}
HTTPcodeCauseWhat to do
404not_foundNo page matches the ref given to /docs/pageSearch first and use a url or id from the result
404not_foundNo manifest by that name at /docs/manifest/{name}Read the manifest list rather than guessing a name
429rate_limitedMore than 240 requests in the last minute from one addressWait, then retry with a widening delay

The message is written for a person reading a log and often names the next call to make. The code is the part to branch on: it is a short string, it does not change wording between releases, and it is what the published description documents.

The response that is not this shape#

Every parameter has bounds — q is 2 to 200 characters, limit on search is 1 to 25, limit on listing is 1 to 1,000, ref is at most 300 characters. A request that violates one is rejected by request validation *before* the handler runs, so it never reaches the code that builds the envelope. That response carries the framework's own detail array naming the offending parameter, with status 422, and the published description's 400 entry describes the malformed-request case rather than this one.

It is worth handling deliberately rather than discovering in production: a client that only knows the error envelope will fail to read the most informative failure it can get, which is the one that names the parameter you got wrong.

GET /api/public/docs/search?q=a HTTP/1.1   -> 422 (q is shorter than 2)
GET /api/public/docs/search?q=email&limit=99 -> 422 (limit exceeds 25)
GET /api/public/docs/page?ref=/docs/nope/    -> 404 {"error": …}
GET /api/public/docs/status                  -> 200

Server-side failure#

An unhandled fault is recorded on the server and answered with a deliberately vague body: no stack trace, no internal path and no identifier that would say anything about another workspace. That is the correct behaviour and it does mean a 5xx gives you nothing to act on beyond *retry once, then stop*.

Distinguish it from the errors above by intent. A 404 and a 422 are your request being wrong and will not improve on retry. A 429 is timing and will. A 5xx is the service, and a client that retries it in a tight loop turns one fault into a rate-limit ban on top of it.

A retry policy that fits this API#

  1. Classify on the status first, then on error.code if there is one.

    Result You get a decision without parsing prose, and one branch for the validation shape that has no code.

  2. Retry only 429 and 5xx, with a widening delay and a cap.

    Result The rate-limit window is sixty seconds, so a few seconds of waiting usually clears it.

  3. On 404 from /docs/page, fall back to a search rather than retrying the same reference.

    Result The reference was wrong, and the error message says so with the search URL to use.

  4. Log the code and the request path, not the whole body.

    Result The codes are a small closed set and count cleanly; messages are prose and do not.

Questions#

Are there more codes than these two?

These are the ones the handlers produce today. The published description also names bad-request and rate-limited responses at the schema level, all using the same envelope, so a client that branches on error.code with a default branch will not break if another is added.

Does an error response carry the cache headers?

No. The five-minute cache header is attached to successful responses only, so a 404 or a 429 is not cached on your behalf and a corrected request is answered fresh.

What do the MCP and A2A endpoints return instead?

JSON-RPC error objects, which are a different shape with numeric codes. See MCP error shapes and Interoperating over A2A.