Errors and recovery
One structured problem contract for REST, MCP and SDK clients.
Read the code, not the English message
REST failures use an application/problem+json envelope. Relevant fields are status, code, title, detail, request_id, retryable, optional retry_after_seconds and action-specific fields such as billing_url. HTTP headers include the support request ID and a retry delay where appropriate.
MCP tool failures use isError:true and structuredContent.error with the same problem semantics. An HTTP 200 MCP transport is not proof of a successful tool. JSON-RPC protocol errors are distinct from a chemistry verdict.
| Code or class | Recovery |
|---|---|
| Authentication/permission errors | Sign in, use a permitted workspace or replace a revoked credential |
validation_error / HTTP 422 | Correct the schema, SMILES, format or option before retrying |
not_found, tool_not_found | Use a returned identifier or supported live action |
credits_exhausted | Inspect live workspace allowance/balance |
sandbox_quota_exhausted | Test quota is exhausted; it is separate from live credit |
workspace_limit_reached, key_limit_reached | Inspect the matching policy and actual reset time |
request_rate_limited | Honor the supplied short retry delay |
| Upstream unavailable/timeout | Retry only when marked retryable; keep request ID |
The SDK preserves unknown future codes rather than assuming the current enum is exhaustive. Branch on stable code; titles/details are explanatory text and may change or be localized.
A scientific negative result is data
An invalid chemical equation can return HTTP 200 with valid:false, and an ambiguous balance can return solved:false. These are successful computations with negative results, not failed transport. Conversely, a failed search must not be presented as “no matching reactions”.
Bounded retries
Fix input errors first. Never loop authentication or exhausted-credit calls. Retry a transient failure only within your task's budget and honor Retry-After. Reuse a write's idempotency key if the network response was lost. Give support request_id rather than credentials or a full private user prompt.