Intercept and control agent behavior with hooks changedagent-sdk/hooks
Nearest release: v2.1.318, published an hour before upstream edited the page. Shown because the two are within 24 hours of each other. Nothing here says the release caused the edit.
Upstream edited this page at 3 Nov 2026 23:05 UTC, give or take a minute or two: the time comes from Anthropic’s own sitemap rather than from a commit. This site recorded the change at 3 Nov 2026 23:07 UTC.
Upstream edited
Recorded here
Lines+49added
Lines−1removed
From line
220
where the diff opens
First seen
14 Aug 2026
this site's first read of the page
Recorded edits22to this page, all time
### Block the action when a callback fails #### Events that behave differently #### Startup errors for `onFailure`
The whole hunk
from line 220, old and new numbered
/
from line 220
220220| `matcher` | `string` | `undefined` | Pattern matched against the event's filter field, following the [rules for matchers in settings files](https://code.claude.com/docs/en/hooks.md#matcher-patterns). For tool hooks, that field is the tool name. Built-in tools include `Bash`, `Read`, `Write`, `Edit`, `Glob`, `Grep`, `WebFetch`, `Agent`, and others. See [Tool Input Types](https://code.claude.com/docs/en/agent-sdk/typescript.md#tool-input-types) for the full list. MCP tools use the pattern `mcp__<server>__<action>`, where `<server>` is the key you use in the `mcpServers` configuration, spelled as the [tool naming convention](https://code.claude.com/docs/en/agent-sdk/mcp.md#tool-naming-convention) describes. |
221221| `hooks` | `HookCallback[]` | - | Required. Array of callback functions to execute when the pattern matches |
222222| `timeout` | `number` | `undefined` | Timeout in seconds. When omitted, Claude Code applies the [event's default timeout](#hook-timeout). Your SDK callbacks follow the `command` hook defaults |
223| `onFailure` | `"continue" \| "block"` | `undefined` | What a failed callback does. Set `"block"` to [block the action when a callback fails](#block-the-action-when-a-callback-fails). In Python, use `on_failure` |
223224
224225Use the `matcher` pattern to target specific tools whenever possible. A matcher with `'Bash'` only runs for Bash commands, while omitting the pattern runs your callbacks for every occurrence of the event.
225226
from line 280
279280>
280281> Async outputs can't block, modify, or inject context into the operation since the agent has already moved on. Use them only for side effects like logging, metrics, or notifications.
281282
283### Block the action when a callback fails
284
285On most events, if a callback throws or returns output that fails validation, the action goes ahead and your app receives an [`SDKInformationalMessage`](https://code.claude.com/docs/en/agent-sdk/typescript#sdkinformationalmessage) warning whose `tag` is `hook_callback_failed`. A `PreToolUse` guard that crashes then lets the tool call reach the normal permission flow. A callback that returns nothing, such as a path with no `return`, also counts as failing. In Python, read `tag` from `SystemMessage.data`.
286
287To block the action instead, set `onFailure: "block"` in TypeScript or `on_failure="block"` in Python on the matcher. Requires TypeScript Agent SDK v0.3.317 or later, or Python Agent SDK v0.2.177 or later. This example blocks a Bash call when `check_policy` in Python or `checkPolicy` in TypeScript fails:
288
289```python Python theme={null}
290options = ClaudeAgentOptions(
291 hooks={
292 "PreToolUse": [
293 HookMatcher(matcher="Bash", hooks=[check_policy], on_failure="block")
294 ]
295 }
296)
297```
298
299```typescript TypeScript theme={null}
300import type { Options } from "@anthropic-ai/claude-agent-sdk";
301
302const options: Options = {
303 hooks: {
304 PreToolUse: [{ matcher: "Bash", hooks: [checkPolicy], onFailure: "block" }]
305 }
306};
307```
308
309To test it, make the callback raise an error and ask Claude to run a Bash command. The tool result includes `failed; blocking because onFailure is "block"`, and Claude doesn't see your error text.
310
311Return `{}` when the callback has no opinion. With `"block"` set, a path with no `return` blocks the action. A callback that catches its own error and returns `{}` isn't failing, so let the error propagate from a guard.
312
313#### Events that behave differently
314
315These events don't always block with `"block"` set:
316
317* **`Stop`, `SubagentStop`, `TaskCompleted`, and `TeammateIdle`**: these events ignore the option, so the action goes ahead.
318* **`PermissionRequest`**: the block counts only if it arrives before your `canUseTool` callback answers.
319* **`PostToolUse`**: the tool has already run, so Claude receives the failure as feedback.
320
321A callback that exceeds its timeout follows [Hook timeout](#hook-timeout). With `"block"` set, a timeout also blocks `PreCompact`, `Elicitation`, and `WorktreeCreate`.
322
323#### Startup errors for `onFailure`
324
325With `"block"` set, the query fails at startup and sends no prompt when it can't honor the option:
326
327* **Claude Code doesn't support the option**: the error includes `does not honor`. Update Claude Code, or remove the option.
328* **The session was already running and didn't register your hooks**: the error includes `did not register your hooks`. Start a new session.
329
282330## Examples
283331
284332Several examples in this section show only the callback function. To run one, register the callback under the matching event in the `hooks` field of your options, as shown in [Configure hooks](#configure-hooks).
from line 823
775823* `Stop` and `SubagentStop`: the timed-out callback counts as returning no decision. The agent or subagent stops as if that callback had allowed it, and a decision from your other hooks on the event still applies. Before Claude Code v2.1.273, a timed-out `Stop` or `SubagentStop` callback counted as a failed hook run, and Claude Code discarded the decisions of your other hooks on the event.
776824* `SessionStart`: the timed-out callback counts as returning no output, and the session continues with the output of your other `SessionStart` hooks.
777825* `PreModelSwitch`: Claude Code blocks the model switch. A hook that doesn't answer hasn't approved the switch.
778* Other events, such as `Notification`, `PreCompact`, and `PostModelSwitch`: Claude Code logs the failure and continues.
826* Other events, such as `Notification`, `PreCompact`, and `PostModelSwitch`: Claude Code logs the failure and continues. With [`onFailure: "block"`](#block-the-action-when-a-callback-fails), a timeout on `PreCompact`, `Elicitation`, or `WorktreeCreate` blocks the action.
779827
780828The first time a `Stop` or `SessionStart` callback times out in the main session, Claude Code also adds an [`SDKInformationalMessage`](https://code.claude.com/docs/en/agent-sdk/typescript#sdkinformationalmessage) to the message stream saying the app driving the session didn't respond. Later timeouts don't repeat that message while your app stays unresponsive.
781829
No line in this hunk matches that.