---
title: "Errors"
summary: "The error shape, the full catalogue of error codes with what each means and what to do, and which status codes are safe to retry."
category: "developer"
tags: ["errors", "error codes", "status codes", "troubleshooting", "retries"]
updated: "2026-09-14T04:25:05.771Z"
url: "https://support.quorumtech.ch/articles/api-errors"
markdown: "https://support.quorumtech.ch/articles/api-errors.md"
---

# Errors

Every error is JSON with a stable machine-readable code and a sentence a person can act on:

```json
{
  "error": {
    "code": "invalid_request",
    "message": "the request body does not match the Attest schema",
    "issues": [
      { "path": "evidence", "message": "provide either evidence or a batchId" }
    ]
  }
}
```

`issues` appears on `invalid_request`, one entry per failing field. `remaining` and `needed` appear on `credits_exhausted`. `cap` and `resetsAt` appear on `monthly_cap_reached`. `failed` appears on `no_files_parsed`, naming each file and why it failed. A refused or failed request never charges credits and carries no credit headers.

Branch on `code`, not on `message`: messages are for people and may be reworded.

## Bulk calls report failures per claim

`POST /attest/v1/attest/bulk` answers 200 whenever the request itself was well formed, even if every claim failed. Read each result's `ok` first: a slot with `ok: false` carries an `error` with a code from the table below (or `indeterminate`, meaning Attest could not measure that claim) and no verdict, so a failure can never be mistaken for a finding.

## The catalogue

| Status | Code | Meaning | What to do |
| --- | --- | --- | --- |
| 400 | `invalid_request` | The body or query does not match the schema. `issues` names each failing field. | Fix the named field. |
| 400 | `location_unavailable` | The `location` is a region the fetching fleet does not offer. | Use one of the regions on the location page. |
| 400 | `invalid_upload` | The multipart body is malformed, uses an unexpected field, or a file could not be read. | Send the documented parts only, and check the file opens. |
| 400 | `batch_not_supported` | A JSON-RPC batch was sent to the MCP surface. | Send one JSON-RPC message per request. |
| 401 | `unauthorized` | The credential is missing, not recognised, revoked, or the wrong kind for this route. | Check the `Authorization` header and the key on the API keys page. |
| 401 | `playground_token_expired` | The documentation playground's token has expired. | Reload the documentation page. |
| 402 | `payment_required` | The workspace has no active API subscription or credits yet. | Claim starting credits, buy a pack or take a plan on the Billing page. |
| 402 | `credits_exhausted` | The balance cannot cover this request. `remaining` and `needed` say by how much. | Add credits or take a plan. |
| 403 | `insufficient_scope` | The key is not scoped to this service. | Create a key that includes it. |
| 403 | `url_not_allowed` | Kerf was asked for an address it does not fetch: a private or loopback address, or a redirect leading to one. | Send a public `http` or `https` address. |
| 403 | `robots_disallowed` | You asked for `followRobots` and the site's robots.txt disallows the page. | Fetch a page the site allows, or leave `followRobots` off for a page you name yourself. |
| 403 | `playground_not_allowed` | The documentation playground tried to reach the MCP surface. | Connect an MCP client with your Quorum account, or use an API key. |
| 404 | `not_found` | No such route. | Check the path against the reference. |
| 404 | `batch_not_found` | The `batchId` names no loaded batch. Batches expire after six hours. | Upload the documents again. |
| 404 | `draft_not_found` | The `draftId` names no uploaded draft. | Upload the draft again. |
| 404 | `job_not_found` | The `jobId` names no review job or extraction. Finished results are kept for a while, and a job belongs to the workspace that started it. | Start the review or the fetch again. |
| 410 | `inputs_deleted` | The draft or the batch was deleted while the review ran. | Upload again and start a new review. |
| 413 | `batch_too_large` | The batch exceeds what the service holds in memory. | Send fewer or smaller documents, or split the batch. |
| 413 | `draft_too_large` | The draft's text is longer than 500,000 characters. | Review it in parts. |
| 413 | `file_too_large` | A draft file over 2 MB, or an evidence file over 25 MB. | Send a smaller file. |
| 422 | `no_files_parsed` | No uploaded file could be parsed. `failed` says why for each. | Check the formats: PDF, Word, PowerPoint, plain text or Markdown. |
| 429 | `rate_limited` | Over the requests-per-minute limit. | Wait `Retry-After`. |
| 429 | `claims_rate_limited` | Over the claims-per-minute ceiling. | Wait `Retry-After`, or send fewer claims at once. |
| 429 | `claim_budget_exhausted` | The day's claims are spent. | Wait for midnight UTC, or raise the key's limit. |
| 429 | `protocol_rate_limited` | Too many MCP protocol messages. | Wait `Retry-After`. |
| 429 | `monthly_cap_reached` | The month's credit cap is reached. `cap` and `resetsAt` say which and when. | Raise the cap on the Billing page, or wait. |
| 429 | `busy` | Kerf's fetching fleet has no room in its queue. | Wait `Retry-After`; it clears in seconds. |
| 429 | `too_many_running` | No room for another draft review right now. | Wait `Retry-After`. |
| 502 | `provider_error` | The model provider behind Attest failed. | Retry with backoff. |
| 424 | `site_refused` | The site answered 401, 403, 407, 429 or 451 and would not serve the page. Nothing is charged. | If you hold the document itself, extract the file instead. |
| 424 | `location_blocked` | `strictLocation` was set and the country could not serve the page: the site refused its addresses twice, or answered a stub. Nothing is charged. | Drop `strictLocation` to take the page from our own address, or drop `location`. |
| 424 | `load_failed` | The page could not be loaded. Nothing is charged. | Retry once; check the address opens in a browser. |
| 424 | `timeout` | The page did not finish loading in time. Nothing is charged. | Try a larger `wait`, or check the address opens in a browser. |
| 502 | `upstream_unavailable` | The service behind the route could not be reached. | Retry with backoff. |
| 502 | `upstream_refused_gateway` | A deployment fault between the gateway and the service, never your credential. | Retry later. If it persists, contact support. |
| 503 | `not_configured` | The evaluator is not configured on this deployment. | Contact support. |
| 503 | `extraction_failed` | No part of the draft could be read. | Check the draft's text, or upload it in another format. |
| 503 | `no_edge_available` | No part of Kerf's fetching fleet is answering. | Retry shortly. |
| 503 | `credits_unavailable` | The balance could not be confirmed. | Retry in a moment. |
| 503 | `ownership_unavailable` | Which workspace a review or an extraction belongs to could not be confirmed. | Retry in a moment. |
| 503 | `review_not_recorded` | A review started but could not be recorded against your workspace, so it could never be collected. | Start the review again. |
| 503 | (verdict `INDETERMINATE`) | Attest could not measure the claim. A server-side failure, never a finding. | Retry. Never read it as a verdict. |
| 504 | `upstream_timeout` | The service did not answer in time. | Retry. For a long review, let it answer 202 and poll. |
| 500 | `internal_error` | Something failed on the server. | Retry once, then contact support with the time and route. |

## What is safe to retry

Retry 429 (after `Retry-After`), 502, 503 and 504 with exponential backoff and jitter. Do not retry 400, 401, 402, 403, 404, 410, 413, 422 or 424 without changing the request: they fail the same way every time, and a 424 is the site's answer, not ours. Claim checks are idempotent but cost a credit each time they succeed, so wait for an answer rather than sending the same check twice.

## Getting help

Every dashboard page has Quincy, the support assistant, in the corner. It can read the documentation, explain a status code from your recent requests, and open a ticket. Include the route, the time, the status and the code when you write in.
