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

# Errors

> The exception hierarchy, what each one means, and why they are not one type.

## The hierarchy

```
RotascaleError
├── Blocked                    policy refused it
│   ├── Exhausted              permitted, but the allowance is spent
│   └── Gated                  untrusted content, and this action needs clean
├── ReviewRequired             a person has to decide
└── EnforcementUnavailable     we could not reach the control plane
```

`Exhausted` and `Gated` subclass `Blocked`, so **order your handlers from
specific to general**. A bare `except Blocked` placed first swallows all three
and you lose the reason, which is the only field that tells you what to do next.

## What each one means

<AccordionGroup>
  <Accordion title="Blocked">
    The policy on the grant refused this action. Genuinely a policy
    conversation: either the agent should not be doing this, or the policy is
    drawn wrongly. Both are worth knowing and they look identical from a log.
  </Accordion>

  <Accordion title="Exhausted">
    The action was permitted and there was no room left, on spend or on call
    count. **Retrying cannot help**, and that is the point of it being a
    separate type. An agent that retries an exhausted grant is burning time
    against a ceiling that will not move until the window rolls or somebody
    raises it.
  </Accordion>

  <Accordion title="Gated">
    Untrusted content entered this trajectory and this action requires a clean
    context. The remedy is not to retry but to look at what was read and where
    it entered. See [Clean context](/concepts/clean-context).
  </Accordion>

  <Accordion title="ReviewRequired">
    Not a refusal. A person has to decide before this proceeds. Carries a
    `review_id` to park on and resume from.
  </Accordion>

  <Accordion title="EnforcementUnavailable">
    Rotascale could not be reached for a decision. Enforcement fails **closed**
    by default, so this raises rather than silently allowing an ungoverned
    action.
  </Accordion>
</AccordionGroup>

## Why not one exception with a code

Because the four refusals send an operator to four different places, and a
single type invites a single handler. "You were not allowed to do that" and
"you had run out" have different owners, different remedies and different
urgency. Merging them costs you the diagnosis at exactly the moment you need it.

## Suppressed decisions

`Decision.suppressed` is true when a refusal was **recorded but not applied**,
which is what `observe` and `shadow` do. The action proceeded; the record says
it would not have. That flag is how you measure a rung before you climb it.
