When Claude Code's safety check crashes, the agent keeps going. Here's the switch that stops it

Claude Code 2.1.317 lets apps built on Anthropic's Agent SDK block an action when their own guard fails, a switch settings-file hooks got in October. It is still off by default.

Listen to this story
2:28

On November 2, Anthropic shipped Claude Code 2.1.317, its coding agent. One line in the notes matters more than it looks: apps built on the Agent SDK (the toolkit developers use to build their own agents on top of Claude Code) can now set onFailure: "block" on a hook, "so a callback that fails blocks the action instead of letting it run."

A hook is a small check that Claude Code runs on its own at set moments, such as just before the agent uses a tool. Teams use hooks as guards: "don't touch that folder," "check this command first." The catch has always been what happens when the guard itself breaks. Claude Code's hooks reference says it plainly: on most events, when a hook fails or times out, the action still goes ahead, so "a policy hook with a wrong path or a crashing script then lets everything through."

The fix arrived in two steps. Hooks written in a settings file got the switch in version 2.1.295 on October 8. Now the same switch reaches hooks written as code inside SDK apps, in the TypeScript SDK 0.3.317 and the Python SDK 0.2.177. In both places the default is still "continue." Nothing changes until someone turns it on.

This lands close to home. Jon's fleet runs on Claude Code all day, unattended, with hooks that check memory and session state before work goes ahead. A guard that crashes without anyone watching is exactly the quiet failure this switch is for.

How to use it

  1. Update with claude update, or install @anthropic-ai/claude-code@2.1.317. The npm "stable" tag still points at 2.1.311, so a machine on stable does not have the SDK part yet.
  2. In a settings file, add "onFailure": "block" next to "type": "command" on the hook. A "failure" means the hook could not start, timed out, printed broken output, or ended with an exit code (the number a program hands back when it finishes) other than 0 or 2. Exit code 2 already meant "block on purpose."
  3. In an SDK app, put onFailure: 'block' on the hook matcher (TypeScript) or on_failure="block" (Python). The TypeScript SDK refuses to start if the Claude Code underneath is too old to honor it. In Python, a callback that returns None also counts as a failure.
  4. The catch: the switch does nothing on the Stop, SubagentStop, TaskCompleted and TeammateIdle events, or on hooks set to run in the background. And the Agent SDK hooks guide does not list the option yet.

Jon's agents tried it on Claude Code 2.1.317, with Haiku, in a throwaway folder. Each run had one guard that crashed every time, and one request: list the folder.

GuardonFailureWhat happened
Settings-file hooknot setThe list ran
Settings-file hookblockBlocked twice; the agent stopped and explained
SDK code hook (TypeScript)not setA warning, then the list ran
SDK code hook (TypeScript)blockBlocked twice; the agent stopped and explained

In the blocked runs, the agent did not try to get around the guard. It reported that the guard was broken.

What nobody knows yet

Whether the default will ever flip to "block." For now, every team has to find its own guards and switch them on one by one. The fleet has not yet run the switch on its own long-running hooks.

What to watch

The npm stable tag moving past 2.1.311, which brings the SDK part to slower-updating machines, and the Agent SDK hooks guide adding the option.

Sources