onFailure: "block" とスクリプト内で exit 2 を返すことの違いは何か?
exit 2 は、スクリプトが正常に動いたうえで「このアクションは許可しない」と宣言するもので、スクリプトが実際に起動してその行に到達することが前提だ。onFailure: "block" が扱うのは、スクリプトがそもそも動かなかった、タイムアウトした、予期せず終了したという、チェック役自体が故障した場合だ。
両者は補い合う関係にある。exit 2 は判定結果を表し、onFailure はチェック役が倒れたときにデフォルトで通過させないことを保証する。
すべての hook に onFailure: "block" を付けるべきか?
付けるべきではない。通知、ログ記録、フォーマットといった補助的な hook が壊れたときは、全体が止まるより続行するほうが良いことが多く、fail-closed はそうした小さな問題を作業の中断に拡大してしまう。
見逃しのコストが誤ブロックのコストを上回るゲート、たとえば本番環境、決済コマンド、顧客データを守る数個にだけ有効にする。
このオプションは公式ドキュメントに載っているか、今すぐ使うべきか?
確認した時点では、公式 hooks ページの読めた範囲にはまだ載っておらず、意味は changelog の1行の説明だけに基づく。フィールドの正確な位置や対象イベントは自分で検証する必要がある。
まずテスト用のプロジェクトでわざと失敗する hook を使って動作を確認し、ドキュメントが整ってからチーム共通の設定に展開するのがよい。
Claude Code v2.1.295(2026年10月8日)は、command と HTTP タイプの hook に onFailure: "block" を追加した。changelog の説明は、hook が起動できない、タイムアウトする、または予期せず終了した場合にそのアクションをブロックする、というものだ。何を解決するのかを知るには、まず従来のデフォルト動作を見る必要がある。
公式の hooks ドキュメントは明確だ。ほとんどのイベントで、スクリプトのパスが存在しない、または実行権限がない場合、shell は 127 などのコードで終了し、Claude Code は非ブロッキングの通知を表示して、アクションは続行される。ドキュメントはさらに、ポリシー用の hook を設定するときは settings.json のパスの打ち間違いでゲートが黙って無効になると警告している。タイムアウトも同じで、PreToolUse でタイムアウトした command、http、mcp_tool の hook はツール呼び出しをブロックせず、止まった hook をゲートとして当てにしないようにと書かれている。HTTP の2xx以外の応答や接続失敗も非ブロッキングのエラーだ。Unix で一般的な失敗コードである exit 1 でさえ、有効な JSON がなければ非ブロッキングで、ブロックするには exit 2 が必要だ。
つまり従来のポリシー hook は fail-open で、チェッカー自体が壊れればチェックは無いのと同じだった。onFailure: "block" を使うと hook ごとに fail-closed を選べる。起動できない、タイムアウトする、予期せず終了するといった場合、通常の権限フローに進まずアクションが止まる。誤ってブロックしても構わないが、見逃しは許されないゲート、たとえば特定のディレクトリへの書き込み、デプロイコマンド、外部のコンプライアンス API に承認を求める hook で特に重要になる。注意点として、私が読めた範囲の公式 hooks ページにはまだこのオプションが載っておらず、上記の意味は changelog の1行の説明に基づく。どの設定フィールドに置くか、どのイベントに効くか、timeout との関係は、更新された公式ドキュメントで確認し、運用前にわざとパスを間違えた hook で自分で検証してほしい。
fail-closed の代償は可用性だ。HTTP hook が頼るコンプライアンスサービスが落ちれば、それが守るすべてのアクションが止まる。本当にリスクの高いゲートにだけ有効にし、予測できるエラーは hook スクリプト内で処理し、その hook をすぐ無効化できる managed settings のスイッチなど明確な逃げ道も用意しておく。また v2.1.295 では claude Plugin validate の hook に関する助言が追加され、v2.1.290 ではゲート型 hook ごとに .catch の有無が一覧できる。この組み合わせで、エラー処理のないゲートを本番前に見つけられる。
チームが hook で触れてはいけないもの、たとえば本番の認証情報、決済関連のコマンド、顧客データのディレクトリを守っているなら、今日棚卸しをしてほしい。壊れたら無言の素通りになる hook はどれか。それを一覧にし、最もリスクの高いいくつかに onFailure: "block" を付け、わざと失敗させるテストを書く。2か月後にゲートがずっと死んでいたと気づくコストは、この10分の確認よりはるかに大きい。