Skip to content

The Checkpoint Meant to Guard You Was Broken—and Waving Everything Through: Claude Code v2.1.295 Lets You Choose to "Stop on Failure"

Fail-open—where a broken safety device silently waves operations through—was the default blind spot. Claude Code v2.1.294/295 fixed an instruction-based hook bug and made it possible to choose "stop on failure" via onFailure:"block." Here are the key points, the differences from other agents, and th

The Checkpoint Meant to Guard You Was Broken—and Waving Everything Through: Claude Code v2.1.295 Lets You Choose to "Stop on Failure"

More and more teams are setting up checkpoints (hooks) in their coding agents to say, "stop here if an operation looks dangerous." But when that checkpoint itself failed to run—because the script was in the wrong place, or it timed out—Claude Code used to let the operation through anyway. The v2.1.294 and v2.1.295 releases that landed on October 8 closed this "wave it through when broken" gap over two days, making it possible to choose behavior that stops the operation on failure.

Operations that should have been blocked were quietly getting through

Hooks are a mechanism that intervenes—for example, right before an agent runs a command—to block operations that violate policy. The problem was what happened when that intervening party itself stopped. By default, the old Claude Code failed open: when a hook couldn't start, timed out, or returned an unexpected exit code, it let the operation through with the guard disabled.

For instance, a single typo in the path to your guard script would silently produce a "disabled safety device," with no warning. If a required dependency wasn't installed and the script bailed out returning exit code 0 (success), even an operation like rm -rf that should have been stopped would slip past the checkpoint. What looked like a guarded gate was, in fact, propped wide open.

Two holes closed over two days

The fix came in two stages.

  • v2.1.294: Fixed a bug where prompt / agent hooks written as instructions—such as "block commands that do X"—would let through operations that should have been blocked. It also revisited how Stop and SubagentStop instruction-based hooks make their decisions, reducing behavior where work was halted too early.
  • v2.1.295: Added onFailure: "block" to command hooks and HTTP hooks. When a hook can't start, times out, or returns an unexpected exit code, you can now choose to block the operation (fail closed) rather than let it through.

With this, teams that use hooks as guards can close the hole where a crashed checkpoint silently lets everything through. Officially, however, prompt, agent, and MCP tool hooks are outside the scope of this protection, and the docs explicitly state, "do not use these as security gates."

How different agents behave when a hook fails

Even with the same "hook," the default behavior when it breaks differs from tool to tool. Here are the differences worth knowing before you adopt them.

ToolDefault on failureHow to stop
Claude CodeFail open (let through)Add onFailure: "block" to stop explicitly (v2.1.295 and later)
CursorFail open (default failClosed: false)failClosed: true per hook. Permission hooks auto-block invalid output via JSON schema validation
CodexLet through (continues processing on unsupported fields or MCP hook errors)No fail-closed toggle is provided
Gemini CLIBlocks on exit code 2; other non-zero codes are treated as warnings and continueReturn exit code 2

The most reliable approach that works across the board is to build your guard so that it exits with exit code 2 when it fails itself. That way you can tip toward blocking in any of the four tools, without relying on version- or product-specific settings.

Settings to put in place right now

For hooks whose purpose is to enforce policy, making these two points your baseline will reduce what slips through.

  • In Claude Code, set onFailure: "block" and a short timeout on all policy-enforcing command / HTTP hooks (requires v2.1.295 or later).
  • On the script side, don't silently end with a success code when preconditions aren't met—stop explicitly with exit code 2.

Conversely, it's safest to accept that prompt, agent, and MCP tool hooks should not be your last line of security defense. Position them as convenience aids, and leave the decision of whether to allow or block to command / HTTP hooks (plus exit codes).

A fix that matters more as automation advances

The more people stop pressing "yes/no" and agents run unattended, the bigger the impact when a checkpoint has quietly broken. This change isn't a flashy new feature, but for operations that felt safe because a guard had "supposedly been set up," it's a quiet, important step that closes a hole capable of causing real harm.

On the other hand, because fail-closed means "stop when broken," a misconfiguration carries the side effect of halting legitimate work too. Getting too greedy with timeout values or block targets can end up stalling your development flow. When tightening a checkpoint, the realistic approach is to watch what gets stopped and what gets through via logs, and clamp down gradually. It's worth building into your automation design the question of whether, behind the convenience, your safety device has become safety in name only.

References: Claude Code changelog (official) / Do Your Agent Hooks Fail Open? Claude Code vs Codex vs Cursor vs Gemini CLI (Developers Digest) / Claude Code 2.1.295 — hooks can fail closed (ai-tldr) / Claude Code Updates (Releasebot)