Developers
Errors
Errors come in layers. Each table is the closed set the code emits.
Protocol codesEarly access
The ARK Record Protocol actions answer an HTTP status and a body of the form {"error": code, "message": text}. Over MCP the same code comes back as the tool result text with isError set.
| Code | HTTP | JSON-RPC | Retry | Code sent by |
|---|---|---|---|---|
schema_invalid | 400 | none | Do not retry; fix the request | REST and MCP |
hash_mismatch | 400 | none | Do not retry; fix the request | REST and MCP |
grant_scope | 403 | none | Do not retry; fix the request | REST and MCP |
subject_reserved | 403 | none | Do not retry; fix the request | REST and MCP |
verbatim_required | 400 | none | Do not retry; fix the request | REST and MCP |
quota_exceeded | 429 | none | Retry after a backoff | REST and MCP |
ingestion_cap | none | none | Retry after a backoff | REST and MCP |
contradicted_pending_review | none | none | Do not retry; fix the request | REST and MCP |
scope_missing | 403 | none | Do not retry; fix the request | REST and MCP |
not_found | 404 | none | Do not retry; fix the request | REST and MCP |
filter_invalid | 400 | none | Do not retry; fix the request | REST and MCP |
not_enabled | 403 | none | Do not retry; fix the request | REST and MCP |
invalid_input | 400 | none | Do not retry; fix the request | REST and MCP |
invalid_cursor | 400 | none | Do not retry; fix the request | REST and MCP |
not_stored | 503 | none | Resend the same request; dedupe makes it safe | REST and MCP |
Gateway refusals
Both gateways refuse a request before any action runs when the credential, the size, the method or the call limit is wrong. The MCP gateway sends the code below; the REST gateway sends an HTTP status and a plain message for most of them, so switch on the status over REST.
| Code | HTTP | JSON-RPC | Retry | Code sent by |
|---|---|---|---|---|
unauthorized | 401 | none | Do not retry; fix the request | MCP (REST sends a status and a message) |
forbidden | 403 | none | Do not retry; fix the request | MCP (REST sends a status and a message) |
rate_limited | 429 | none | Retry after a backoff | MCP (REST sends a status and a message) |
payload_too_large | 413 | none | Do not retry; fix the request | MCP (REST sends a status and a message) |
method_not_allowed | 405 | none | Do not retry; fix the request | MCP (REST sends a status and a message) |
unsupported_protocol_version | 400 | none | Do not retry; fix the request | MCP (REST sends a status and a message) |
server_error | 500 | none | Retry after a backoff | MCP (REST sends a status and a message) |
source_key_forbidden | 403 | none | Do not retry; fix the request | REST and MCP |
not_recorded | 503 | none | Resend the same request; dedupe makes it safe | REST and MCP |
entitlement_revoked | 401 | none | Do not retry; fix the request | REST and MCP |
master_dormant | 403 | none | Do not retry; fix the request | REST and MCP |
Over REST the gateway refusals marked MCP are sent as an HTTP status and a plain message ({"error": "<message>"}: 401 for a missing or invalid credential, 405, 429 for the call limit, 500); source_key_forbidden and the entitlement codes arrive in a code field beside the message. Switch on the HTTP status over REST, on the code over MCP.
MCP JSON-RPC codes
The MCP server answers a malformed call with a JSON-RPC error object. A tool that runs and fails answers a normal result with isError true: a live tool's text starts with "Error:"; a protocol tool's text is the same JSON body REST would send, {"error": "<code>", "message": "..."}.
| Code | HTTP | JSON-RPC | Retry | Code sent by |
|---|---|---|---|---|
parse_error | 400 | -32700 | Do not retry; fix the request | MCP (REST sends a status and a message) |
invalid_request | none | -32600 | Do not retry; fix the request | MCP (REST sends a status and a message) |
method_not_found | none | -32601 | Do not retry; fix the request | MCP (REST sends a status and a message) |
invalid_params | none | -32602 | Do not retry; fix the request | MCP (REST sends a status and a message) |
internal_error | 500 | -32603 | Retry after a backoff | MCP (REST sends a status and a message) |
source_key_forbidden | none | -32003 | Do not retry; fix the request | MCP (REST sends a status and a message) |
not_recorded | none | -32000 | Resend the same request; dedupe makes it safe | MCP (REST sends a status and a message) |
The live actionsLive
get_ark_profile, search_ark_topics and ask_ark answer an HTTP status and a plain message, {"error": message}, with no code. Over MCP the message comes back as isError text. Retry a 429 or a 5xx after a backoff; fix the request for a 4xx.
duplicate is a result, not an errorEarly access
A proposal your source already sent answers HTTP 200 with status duplicate and duplicate_of naming the first proposal. Nothing new is stored and no quota is used twice. Treat it as success.