Docs

Errors

Handle Scry HTTP error envelopes, status codes, retry guidance, and long-query failures.

Error shape

Application errors emitted by Scry handlers use JSON shaped as {"error":{"code":"...","message":"...","details":...}}. The details field is omitted when the error has no structured detail. Retryable responses can include the Retry-After header. Framework-level JSON parsing failures can use a different response shape.

{
  "error": {
    "code": "invalid_request",
    "message": "Missing Content-Type. Use text/plain, text/sql, application/sql, or application/json."
  }
}

Status codes

The routes documented here return the following status and code families.

StatusCodes and meaning
400`invalid_request` for unsupported content types, invalid SQL, or endpoint validation failures; `query_exposure_exhausted` when raw machine burden crosses `x-scry-budget` (MCP `budget_nanodollars`), with `burden_nanodollars`, `elapsed_ms`, and `kill_source` in details and nothing partial returned. JSON extractor failures can use a framework response.
401`unauthorized` when the bearer credential is missing, malformed, or invalid.
402`insufficient_credits` or the query payment challenge when funds or payment authorization are required.
403`forbidden` when account state or key scope denies the request.
405`method_not_allowed`; the SQL route also returns `Allow: POST`.
408`request_timeout` or `runtime_deadline_exceeded` when execution exceeds its deadline, or when the forecast alone does (the message then says the statement was refused before execution). The deadline is 15 s with no header; `x-scry-max-seconds` raises it to at most 2000 s under an account key (a larger value is clamped, and the envelope reports what ran as `authorized_seconds`), 60 s on the x402 lane, and 1800 s for a program.
409`intent_settled` when an `idempotency-key` (MCP `idempotency_key`) identifies a statement that already settled: details include `query_id`, `row_count`, `settled_at`, and `spend_nanodollars`, and nothing runs again.
429`rate_limited`, `query_capacity_exhausted`, or `priced_out` (posted congestion multiplier above your `x-scry-max-multiplier` ceiling); inspect `Retry-After`.
500`internal_error` when the server cannot complete internal work.
503`service_unavailable` when an endpoint, provider set, admission channel, or dependency is unavailable.

Gateway errors

A 502 or 504 with no JSON error envelope comes from the gateway in front of the application, not from a Scry handler: the SQL is not at fault and rewriting it changes nothing, but whether the statement ran is unknown — a 502 is a refused connection or a broken reply, a 504 a reply that did not arrive in time, and either can land after the engine began work. Name the intent (idempotency-key header, MCP idempotency_key) and the retry answers for itself: if the first attempt settled, the door returns intent_settled with its query_id, row_count, and spend_nanodollars instead of running it again; if it never ran, it runs once. https://status.scry.io reports disruptions independently of the API.

Long queries

After the synchronous grace period, the SQL route can begin a 200 application/json stream and send whitespace while execution continues. A later failure then appears as the same JSON error object inside that 200 response because the HTTP status has already been sent. Check the body for error before treating a long-query response as a result.

Related docs

Want even more out of Scry? Think there's something we can do? Reach out with a request or an offer at hi@scry.io.