> ## Documentation Index
> Fetch the complete documentation index at: https://checkfu.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Errors

> Handle Checkfu's stable typed error envelope and retry only what is safe to retry.

Every versioned JSON error uses the same typed envelope:

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
  "error": {
    "type": "runtime.invalid_transition",
    "message": "cannot drive a terminal session",
    "more": "https://docs.checkfu.com/reference/errors#runtime-invalid-transition"
  }
}
```

Switch on `error.type`, not on the human-readable message. Messages are written for humans and may be reworded; the type is contract. Every error includes a stable `more` URL that links directly to its catalog entry. A documented type can add structured recovery data inside `error`; for example, `validation.prompt_integrity_review_required` adds a `review` challenge. The same envelope is returned across every endpoint, including [Session and Run](/concepts/sessions-and-runs) operations.

## Namespaces

The prefix tells you who has to act.

| Namespace    | Meaning                                                             | Who resolves it               |
| ------------ | ------------------------------------------------------------------- | ----------------------------- |
| `validation` | The request is malformed, missing, conflicting, or too large.       | The caller                    |
| `auth`       | The API key is missing, unknown, revoked, or wrong-scope.           | The caller                    |
| `policy`     | Governance denied the action.                                       | A Workspace administrator     |
| `budget`     | A capacity ceiling was reached.                                     | A Workspace administrator     |
| `billing`    | Commercial entitlement blocks Checkfu-funded work.                  | An Organization administrator |
| `model`      | Model routing or provider credentials failed.                       | A Workspace administrator     |
| `memory`     | A MemoryStore or document operation failed.                         | Varies                        |
| `runtime`    | Execution machinery failed, or was asked for an illegal transition. | Usually Checkfu               |

User-correctable errors carry enough detail to fix the request, so a model driving the API can self-correct. Internal failures return an opaque incident reference instead of a stack trace or secret-bearing context.

## Error registry

| Type                                                                                                   | HTTP | Safe to retry |
| ------------------------------------------------------------------------------------------------------ | ---: | ------------- |
| <a id="validation-malformed">validation.malformed</a>                                                  |  400 | No            |
| <a id="validation-prompt-integrity-review-required">validation.prompt\_integrity\_review\_required</a> |  400 | No            |
| <a id="validation-not-found">validation.not\_found</a>                                                 |  404 | No            |
| <a id="validation-conflict">validation.conflict</a>                                                    |  409 | No            |
| <a id="validation-idempotency-conflict">validation.idempotency\_conflict</a>                           |  409 | No            |
| <a id="validation-idempotency-in-progress">validation.idempotency\_in\_progress</a>                    |  409 | Yes           |
| <a id="validation-payload-too-large">validation.payload\_too\_large</a>                                |  413 | No            |
| <a id="validation-range-too-large">validation.range\_too\_large</a>                                    |  422 | No            |
| <a id="auth-invalid-key">auth.invalid\_key</a>                                                         |  401 | No            |
| <a id="auth-disabled-tenancy">auth.disabled\_tenancy</a>                                               |  403 | No            |
| <a id="policy-denied">policy.denied</a>                                                                |  403 | No            |
| <a id="budget-exceeded">budget.exceeded</a>                                                            |  429 | No            |
| <a id="model-no-eligible-model">model.no\_eligible\_model</a>                                          |  422 | No            |
| <a id="model-credential-rejected">model.credential\_rejected</a>                                       |  422 | No            |
| <a id="model-platform-supply-unavailable">model.platform\_supply\_unavailable</a>                      |  503 | Yes           |
| <a id="model-platform-capacity-reached">model.platform\_capacity\_reached</a>                          |  503 | Yes           |
| <a id="billing-entitlement-unavailable">billing.entitlement\_unavailable</a>                           |  503 | Yes           |
| <a id="billing-usage-limit-reached">billing.usage\_limit\_reached</a>                                  |  402 | No            |
| <a id="billing-payment-required">billing.payment\_required</a>                                         |  402 | No            |
| <a id="billing-seat-activation-unavailable">billing.seat\_activation\_unavailable</a>                  |  503 | Yes           |
| <a id="memory-not-found">memory.not\_found</a>                                                         |  404 | No            |
| <a id="memory-conflict">memory.conflict</a>                                                            |  409 | No            |
| <a id="memory-read-only">memory.read\_only</a>                                                         |  403 | No            |
| <a id="memory-invalid-path">memory.invalid\_path</a>                                                   |  400 | No            |
| <a id="memory-backend-unavailable">memory.backend\_unavailable</a>                                     |  503 | Yes           |
| <a id="memory-curation-failed">memory.curation\_failed</a>                                             |  422 | No            |
| <a id="runtime-invalid-transition">runtime.invalid\_transition</a>                                     |  409 | No            |
| <a id="runtime-primary-thread">runtime.primary\_thread</a>                                             |  409 | No            |
| <a id="runtime-checkpoint-expired">runtime.checkpoint\_expired</a>                                     |  409 | No            |
| <a id="runtime-session-history-unavailable">runtime.session\_history\_unavailable</a>                  |  409 | No            |
| <a id="runtime-harness-unavailable">runtime.harness\_unavailable</a>                                   |  503 | Yes           |
| <a id="runtime-harness-failed">runtime.harness\_failed</a>                                             |  502 | Yes           |
| <a id="runtime-runner-unavailable">runtime.runner\_unavailable</a>                                     |  503 | Yes           |
| <a id="runtime-lease-lost">runtime.lease\_lost</a>                                                     |  409 | No            |
| <a id="runtime-start-timeout">runtime.start\_timeout</a>                                               |  503 | Yes           |
| <a id="runtime-provisioning-suspended">runtime.provisioning\_suspended</a>                             |  503 | Yes           |
| <a id="runtime-turn-deadline-exceeded">runtime.turn\_deadline\_exceeded</a>                            |  504 | No            |
| <a id="runtime-observation-gap">runtime.observation\_gap</a>                                           |  409 | Yes           |
| <a id="runtime-observation-conflict">runtime.observation\_conflict</a>                                 |  409 | No            |
| <a id="runtime-attestation-invalid">runtime.attestation\_invalid</a>                                   |  400 | No            |
| <a id="runtime-harness-incompatible">runtime.harness\_incompatible</a>                                 |  422 | No            |
| <a id="runtime-internal">runtime.internal</a>                                                          |  500 | Yes           |

`validation.payload_too_large` always names a specific documented ceiling. [Request and payload limits](/reference/lookup#request-and-payload-limits) lists every one of them, and which of them refuse with a `413` rather than a `400`.

`validation.range_too_large` is its read-side counterpart, and the distinction is worth holding: the request is well formed, but your Workspace's data density exceeds what the read can decode. It is never a truncated answer. Whether a narrower range fixes it depends on which read you called, and the message says which case you are in — a **grouped** read replays the whole requested range, so narrowing works, while the **Workspace-total** read replays a roughly 48-hour tail anchored to `as_of` rather than to your request, so narrowing does not reduce it.

`runtime.attestation_invalid` appears only on the connected-runtime observation path: a signed observation batch whose Ed25519 signature, runtime registration, or placement does not verify. Ordinary API clients never produce it.

`runtime.provisioning_suspended` settles a Run after several consecutive provisioning failures in a short window: the sandbox provider kept refusing or never became ready, so the platform stops burning provider attempts for a short cooldown instead of retrying forever. It clears itself — the next Run after the cooldown provisions normally, and a single successful start resets the count.

## Retry guidance

Retry only the types marked **Yes** above.

Retry those with exponential backoff and jitter, capping the number of attempts. Everything else is a decision, not a transient failure: the request, the configuration, or an approval has to change before it can succeed. Retrying a `policy.denied` or a `runtime.invalid_transition` fails identically every time.

Three retryable types are worth calling out because they are easy to misread:

* `validation.idempotency_in_progress` means another request carrying the same `Idempotency-Key` is still in flight. Back off and retry the identical request; you receive the first request's result rather than causing a second mutation.
* `runtime.observation_gap` means execution evidence arrived out of order. The Run is intact and the write is safely repeatable.
* `memory.backend_unavailable` means the versioned [MemoryStore](/concepts/memory) backend cannot serve the operation and the write was not applied. When an enabled backend is unhealthy, back off and retry. In the hosted alpha the versioned surface is intentionally disabled pending D7, so retries cannot make those fenced endpoints succeed. A document body that retention refuses is a different answer entirely: it returns `403 policy.denied`, never this type, so no amount of retrying stores it.

<Warning>
  `memory.read_only` is never retryable, and one of its causes is easy to mistake for a race: a write against an **archived** MemoryStore returns `403 memory.read_only`, not a `409`. Archiving is not a transient state, so retrying never clears it.
</Warning>

## Errors that need an upstream change

| Type                              | What actually happened                                                                                                                                                                                                                                                                                                                                                                    |
| --------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `budget.exceeded`                 | Some capacity ceiling was reached: a customer-configured [Budget](/concepts/automations), a Workspace monthly quota, a ToolInvocation ceiling, or an API-key rate limit. It does **not** specifically mean a Budget resource was breached.                                                                                                                                                |
| `billing.payment_required`        | The Organization's payment is past due. Reads, exports, and login continue; new Checkfu-funded work does not.                                                                                                                                                                                                                                                                             |
| `billing.usage_limit_reached`     | Commercial entitlement is exhausted. Distinct from `budget.exceeded`, which is a self-imposed customer limit.                                                                                                                                                                                                                                                                             |
| `policy.denied`                   | Either governance returned `deny` (no PermissionAssignment matched, or an ActionPolicy rule denied it; see [Tenancy and governance](/concepts/tenancy-and-governance)), or retention refused to store a [MemoryStore](/concepts/memory) document body: the Workspace is zero-data-retention, or the content's retention ceiling has already elapsed. Both are settled answers, not races. |
| `model.no_eligible_model`         | Every candidate in the [ModelRoutingProfile](/concepts/harnesses-and-models) violated a Workspace provider constraint. Routing fails closed rather than silently choosing a disallowed model.                                                                                                                                                                                             |
| `model.credential_rejected`       | A Workspace provider key was present but rejected. An invalid override never falls back to platform supply.                                                                                                                                                                                                                                                                               |
| `validation.idempotency_conflict` | The same `Idempotency-Key` was reused with a **different** request body.                                                                                                                                                                                                                                                                                                                  |

## CLI exit codes

Scripted callers get a stable, closed **failure-class** axis: the CLI maps every error to one process exit code, keyed on the kind of failure rather than the specific `error.type`. This lets a script branch on `$?` without parsing JSON.

| Exit | Class         | Covers                                                                                                                                                                                                                                                                    |
| ---- | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `0`  | success       | No failure                                                                                                                                                                                                                                                                |
| `1`  | usage         | `400` request-shape or review errors (`validation.malformed`, `validation.prompt_integrity_review_required`), any other unmapped `4xx` including `413 validation.payload_too_large`, bad CLI invocation, or a domain-outcome failure the transport delivered successfully |
| `2`  | network       | Transport failure reaching the API                                                                                                                                                                                                                                        |
| `3`  | auth          | `401`/`403`: `auth.invalid_key`, `policy.denied`                                                                                                                                                                                                                          |
| `4`  | not\_found    | `404 validation.not_found`                                                                                                                                                                                                                                                |
| `5`  | conflict      | `409` conflicts (`validation.idempotency_conflict`, `runtime.invalid_transition`, …)                                                                                                                                                                                      |
| `6`  | invalid       | `422` unprocessable: a semantically valid shape the platform can't act on (`model.no_eligible_model`, `runtime.harness_incompatible`, `memory.curation_failed`)                                                                                                           |
| `7`  | rate\_limited | `429 budget.exceeded`                                                                                                                                                                                                                                                     |
| `8`  | server        | `5xx`                                                                                                                                                                                                                                                                     |
| `9`  | billing       | `402`: `billing.payment_required`, `billing.usage_limit_reached`                                                                                                                                                                                                          |

`130` and `143` are reserved for `SIGINT`/`SIGTERM`. Exit codes signal the *kind* of failure only. A run's actual result still comes from the [event log](/reference/events), and a task that ran but failed its rubric is a successful transport (exit `1` as a usage-level outcome), not a transport error.

## Next steps

<CardGroup cols={2}>
  <Card title="Quickstart" icon="rocket" href="/getting-started/quickstart">
    Drive your first Run end to end and see these error types in context.
  </Card>

  <Card title="API reference" icon="book" href="/reference/overview">
    Browse the endpoints and shapes that emit this error envelope.
  </Card>
</CardGroup>
