Every application error teaches. The common envelope is:

```json
{
  "error": "<stable code>",
  "message": "<what happened>",
  "hint": "<the corrected next step>"
}
```

## Categories

- `invalid_input`: the request shape or value is wrong; follow the corrected example.
- `unknown_tool`: return to `discover`; a catalog tool id was not accepted.
- `connection_required`: the human must connect a provider account at `connect_url`.
- `insufficient_balance`: the human must add funds at `topup_url`.
- `confirmation_required`: the human must approve the quoted estimate at `approval_url`.
- `conflicting_tool_id`: send one canonical `tool_id`, or matching values during the compatibility window.
- `run_failed`: the run ended without success; read the provider or execution hint and remember that its hold was released.

## Retry discipline

Do not blindly repeat a paid call. First classify the error, follow its hint and decide whether the same input is safe to send. A timed-out HTTP request is not evidence that a provider run did not start; use the existing `run_id` or inspect the run record.

## Transport boundary

Malformed JSON-RPC is a protocol error because no tool call was understood. A well-formed tool failure is returned as a tool result with `isError: true`, keeping the message and hint in the model's context.

For examples of the control-tool contracts, return to [control tools](https://scrollport.com/docs/control-tools).