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

# Errors

> The closed set of CTRLRun exceptions, each with its base class and when it is raised: ActionDenied, ApprovalRequired, DuplicateEffect and the rest.

Every refusal is an exception of its own, raised as itself before the executor runs, so an
agent loop can tell them apart with `except`. All of them derive from `CTRLRunError`; the
set is closed by the specification and a new one is a specification amendment first.

| Exception             | Base           | Raised when                                                                            |
| --------------------- | -------------- | -------------------------------------------------------------------------------------- |
| `CTRLRunError`        | `Exception`    | Base class for every error raised by CTRLRun.                                          |
| `InvalidArgument`     | `CTRLRunError` | An argument cannot be accepted as given.                                               |
| `PolicyError`         | `CTRLRunError` | The policy is missing, unreadable, or malformed. Raised at load time (SPEC-v0.1 §3.4). |
| `EffectKeyError`      | `CTRLRunError` | An effect template cannot be resolved to a key (SPEC-v0.1 §5.1).                       |
| `ActionDenied`        | `CTRLRunError` | The action may not run. `reason` says why, e.g. `unknown_action` (SPEC-v0.1 §3.4).     |
| `AuthorityDenied`     | `ActionDenied` | The principal holds no grant that covers this action (SPEC-v0.3 §4.3).                 |
| `AuthorityEscalation` | `CTRLRunError` | A delegation that may not exist: it is not contained in its parent (SPEC-v0.3 §5.3).   |
| `ApprovalRequired`    | `CTRLRunError` | The action needs a human. `request_id` is what `ctrlrun approve` takes (SPEC §4.3).    |
| `ApprovalTimeout`     | `CTRLRunError` | Nobody answered the approval request in time (SPEC-v0.1 §4.3).                         |
| `ApprovalMismatch`    | `CTRLRunError` | The presented approval does not authorize this action (SPEC-v0.1 §4.2).                |
| `DuplicateEffect`     | `CTRLRunError` | This logical effect already happened, or is happening now (SPEC-v0.1 §5.4).            |
| `AmbiguousEffect`     | `CTRLRunError` | The outcome of this effect is unknown; only a human may resolve it (SPEC-v0.1 §5.4).   |
| `NotExecuted`         | `CTRLRunError` | Raised by an executor to assert the remote side did nothing (SPEC-v0.1 §5.5).          |
| `Suspended`           | `CTRLRunError` | Raised by an executor: the remote asked for something before it will finish.           |
| `IdentityError`       | `CTRLRunError` | A credential was offered and rejected (SPEC-v0.3 §3.2).                                |
| `SchemaMismatch`      | `CTRLRunError` | A store met a database it does not recognise, in either direction (SPEC-v0.6 §3.3).    |
| `MissingDependency`   | `CTRLRunError` | An optional extra is not installed (SPEC-v0.2 §1.1, §11).                              |

## Each one

### CTRLRunError

Base class for every error raised by CTRLRun.

### InvalidArgument

An argument cannot be accepted as given.

An Action field or argument that cannot be canonicalized (SPEC-v0.1 §2.3), and — the
same kind of wiring bug — a StateStore transition no record can make, such as committing
an effect nobody reserved.

### PolicyError

The policy is missing, unreadable, or malformed. Raised at load time (SPEC-v0.1 §3.4).

### EffectKeyError

An effect template cannot be resolved to a key (SPEC-v0.1 §5.1).

The action is refused rather than executed without an effect key: an action whose
logical effect cannot be identified cannot be protected against duplication.

### ActionDenied

The action may not run. `reason` says why, e.g. `unknown_action` (SPEC-v0.1 §3.4).

### AuthorityDenied

The principal holds no grant that covers this action (SPEC-v0.3 §4.3).

A subclass of `ActionDenied`, because an authority denial *is* the action being denied and
an agent loop's existing `except ActionDenied` should keep working. `reason` is one of the
closed set in §4.3 — `no_authority`, `authority_constraint`, `authority_expired`,
`authority_escalation`, `authority_revoked`, `authority_unreadable` — never a grant id: a
grant may legally be named `no_authority`, and evidence that can be spoofed by naming a
grant is not evidence. The id travels in `grant_id`.

### AuthorityEscalation

A delegation that may not exist: it is not contained in its parent (SPEC-v0.3 §5.3).

Not an `ActionDenied`: nothing was proposed. This is the creation-time vocabulary —
`containment`, `unknown_parent`, `parent_not_delegable`, `parent_not_valid`,
`not_the_subject`, `max_depth` — and it is disjoint from `AuthorityDenied`'s evaluation
reasons. The two are never used interchangeably.

### ApprovalRequired

The action needs a human. `request_id` is what `ctrlrun approve` takes (SPEC §4.3).

Raised instead of blocking, so an agent loop can surface the request and come back with
`ctrlrun.with_approval(request_id)` in context.

### ApprovalTimeout

Nobody answered the approval request in time (SPEC-v0.1 §4.3).

### ApprovalMismatch

The presented approval does not authorize this action (SPEC-v0.1 §4.2).

`reason` is one of `unknown`, `mismatch`, or the status the record was in — `consumed`,
`expired`, `pending`, `denied`.

### DuplicateEffect

This logical effect already happened, or is happening now (SPEC-v0.1 §5.4).

`state` is `committed` — the effect is done — or `in_progress`, meaning another attempt
holds a live reservation on the key. Neither permits a second execution.

### AmbiguousEffect

The outcome of this effect is unknown; only a human may resolve it (SPEC-v0.1 §5.4).

Raised for a record already in `AMBIGUOUS`, and for one whose lease expired mid-flight:
the worker may have died after the remote committed. A retry is refused either way,
until `ctrlrun resolve` says which it was.

### NotExecuted

Raised by an executor to assert the remote side did nothing (SPEC-v0.1 §5.5).

This is the *only* exception that maps to `FAILED` and therefore permits a retry.
Every other exception is an `AMBIGUOUS` outcome.

### Suspended

Raised by an executor: the remote asked for something before it will finish.

SPEC-v0.2 §6.9 in the kernel's own terms, and modelled the way v0.1 §5.5 models "nothing
happened" — an explicit opt-in signal, never a default and never inferred. There is no
outcome to record: the effect record stays `EXECUTING`, its lease is extended, the
continuation is held, and the caller gets this back to relay.

`continuation` is whatever the remote said to present again. It is opaque here — CTRLRun
never parses it, and only ever compares it with `hmac.compare_digest`.

### IdentityError

A credential was offered and rejected (SPEC-v0.3 §3.2).

Not an `ActionDenied`: an agent loop's `except ActionDenied` is written to handle a policy
saying no, and a credential that stopped being valid is not that — the same distinction
v0.1 §5.1 draws for `EffectKeyError`. A *missing* principal stays
`ActionDenied(reason="no_principal")`; this is for one that was produced and found wanting,
which includes an expired `Principal` reaching `Control.execute` (§2.3).

### SchemaMismatch

A store met a database it does not recognise, in either direction (SPEC-v0.6 §3.3).

Its own type rather than an `InvalidArgument`, and the bar it clears is that an operator's
process refusing to start needs a distinguishable exception: *"your database is from the
future"* and *"your lease is negative"* have entirely different remedies, and one bucket for
both would put a schema problem behind a wiring bug.

### MissingDependency

An optional extra is not installed (SPEC-v0.2 §1.1, §11).

Never `ImportError` or `ModuleNotFoundError`: an operator reads those as a broken
package rather than as an option they did not select. The message names the module that
is missing and the command that installs it.

## Next

* [Fail closed](/concepts/fail-closed): the table of what is refused, and where.
* [Outcomes and AMBIGUOUS](/concepts/outcomes-and-ambiguous): `NotExecuted` and why it is the dangerous one.
* [Get started](/get-started/quickstart) · [Why](/why).


## Related topics

- [CTRLRunError](/reference/api/CTRLRunError.md)
- [PolicyError](/reference/api/PolicyError.md)
- [IdentityError](/reference/api/IdentityError.md)
- [EffectKeyError](/reference/api/EffectKeyError.md)
- [MissingDependency](/reference/api/MissingDependency.md)
