Claude Code v2.1.295 adds an onFailure setting for command and HTTP hooks. Set to "block", a hook that fails to start, times out or returns invalid output now stops the action instead of letting it through. For teams that use hooks as guardrails, it closes a gap where a broken policy script silently allowed everything.
What was released
The setting was announced by Anthropic on 8 October 2026 in the Claude Code v2.1.295 release notes, and is documented in the Claude Code hooks reference. It needs Claude Code v2.1.295 or later and is configured per hook handler in the same settings files that already hold your hooks, so access is a matter of updating Claude Code and adding one field.
What actually changed
Until now, a hook that failed was a non-blocking error. The hooks reference is direct about the consequence: on most events, a policy hook with a wrong path or a crashing script lets everything through, and the user only sees a hook error notice in the transcript.
The new onFailure field takes "continue" (the default, the old behaviour) or "block". With "block", the documentation counts these as failures:
- Can't start: the script or executable doesn't exist.
- Unexpected exit code: anything other than 0 or 2, even if the hook printed JSON allowing the action.
- HTTP error: an HTTP hook's connection fails or the status isn't 2xx.
- Timeout: the hook reaches its timeout (600 seconds by default for command and HTTP hooks).
- Invalid output: JSON that can't be parsed or fails schema validation.
A blocked failure behaves like exit code 2 on that event: a PreToolUse failure blocks the tool call, a UserPromptSubmit failure blocks the prompt, and on PermissionRequest the request is denied. Exit code 2 itself is unchanged and still means "block on purpose".
The limits matter as much as the feature. onFailure applies only to command and http hooks, not to prompt, agent or mcp_tool hooks. It has no effect on command hooks that run in the background (async or asyncRewake), or on Stop, SubagentStop, TaskCompleted and TeammateIdle hooks, where blocking would only send Claude back to work on something it cannot repair.
What it means for teams using Claude Code with guardrails
Many teams have put real policy into hooks: blocking destructive shell commands, keeping agents out of production config, checking commands against an internal service. Each of those was quietly fail-open. A renamed script, a missing Node module on a new laptop or a slow policy endpoint turned the guardrail off without anyone deciding to. In CodeDTX's view, these are the practical steps:
- Sort your hooks into guardrails and helpers. A PreToolUse hook that decides whether a command may run is a guardrail and should fail closed. A formatter, a logger or a notification hook is a helper and should keep the default, or a broken helper will stop work for no safety gain.
- Set explicit timeouts on HTTP policy hooks. With
"block", a slow policy service now stops the agent rather than being ignored. A short, deliberate timeout plus a reliable endpoint is better than discovering the default during an outage. - Fix the exit codes in your scripts. Under
"block", a script that exits 1 after printing an allow decision now blocks. Make sure decisions exit 0, deliberate blocks exit 2, and anything else is a genuine failure. - Roll it out through managed settings once tested. Try it with a small group, collect the blocks that real work produces, then put the guardrail hooks with
onFailure: "block"into the settings your organisation manages, so they cannot be dropped on individual machines. - Keep a record of what was blocked. A blocked action is evidence of a control working, or of a broken script. Either way it belongs in the same place as the rest of an AI agent audit trail.
When fail-closed is the wrong choice
Blocking on failure trades availability for safety. For hooks whose only job is convenience, it simply makes the agent fragile. It also does not make a hook correct: a policy script that allows the wrong command, and exits cleanly, still lets it through. Hooks are one layer; they sit alongside sandboxing, permissions and human approval for consequential steps, as covered in stopping an agent taking a wrong action and the AI agent attack surface. And because prompt and agent hooks are outside its scope, a guardrail that depends on a model's judgement still fails open when it errors.
Frequently asked questions
What does onFailure block do in Claude Code hooks?
It makes a failing command or HTTP hook stop the action instead of allowing it. A failure includes a script that cannot start, an exit code other than 0 or 2, an HTTP error, a timeout, or output that is not valid JSON. With the setting on, the failure has the same effect as exit code 2 on that event, so a PreToolUse failure blocks the tool call.
Which Claude Code version and hook types support onFailure?
It needs Claude Code v2.1.295 or later, released by Anthropic on 8 October 2026. It works only on command and HTTP hooks. Prompt, agent and MCP tool hooks do not support it, background command hooks ignore it, and it has no effect on Stop, SubagentStop, TaskCompleted and TeammateIdle hooks, where a block would only send Claude back to work.
Should every hook use onFailure block?
No. Use it for hooks that enforce policy, such as checks that decide whether a shell command or file edit may proceed. Leave the default for helpers such as formatters, loggers and notifications, because a broken helper would otherwise stop the agent with no safety benefit. Reviewing each hook against that split is a quick exercise and avoids both silent gaps and needless interruptions.
What happens to a hook that times out without onFailure?
By default, a timeout is a non-blocking error. The hooks reference says that for command, HTTP and MCP tool hooks a PreToolUse timeout does not block, and the call carries on through the normal permission flow. Setting onFailure to block on a command or HTTP hook changes that, so the tool call is stopped when the hook reaches its timeout.



