ブログ • Claude Code / Agent SDK

Claude Code 2.1.317 に上げ、Agent SDK hook で onFailure を block にしたとき、コールバック失敗の拦截を JSON ログにどう書くか?

2026年11月3日 Anthropic は Claude Code 2.1.317 を出した。Agent SDK hook コールバックに onFailure block を追加。PreToolUse 等の hook 脚本が非零終了や timeout のとき fail-open せず tool 动作を拦截し監査 JSON に blocked を書く。

hook 回调结果 JSON に hookName、onFailure block、exitCode、timedOut を書く。拦截後の監査 JSON に decision blocked、reason hook_callback_failed、hookName、exitCode。运维は hook_failure_gate の schema、not_block_mode、allow、block、timeout_block と照合し、回调失败を permission policy deny と混同しない。

allow と deny キューは Agent permission policy。Managed Agents の auto 評価文脈は Managed Agents auto 評価。セッション工作流 JSON は Claude Code workflow。本記事は 2.1.317 の onFailure block、hooks settings と回调结果 JSON、Bash 呼び出し、hook_callback_failed 監査フィールド、hook_failure_gate 分岐のみを書く。

先にこれだけ:2.1.317 が変えるのは hook 回调失败時の block 语义と hook_callback_failed 監査フィールドであり permission policy の allow deny 表の書き換えではない。以下 changelog、hooks settings JSON、回调结果 JSON、Bash 呼び出し、監査ログと表、hook_failure_gate 源码、JSONNote での形状検証。

2.1.317 は hook 回调失败時に fail-open ではなく block するには

変更は Claude Code changelog、タグは v2.1.317 release。以前の Agent SDK hook 行为比で目立つのは onFailure block。PreToolUse 等が非零終了や timeout なら警告だけで続行せず tool 动作を拦截する。

拦截は hook 回调完了後・tool 実行前。監査 JSON に decision blocked、reason hook_callback_failed、hookName、exitCode を残し、汎用 tool denied ではなく失敗 hook で SIEM 帰属する。

PreToolUse と onFailure block を hooks settings JSON にどう書くか

ユーザーまたはプロジェクト settings の hooks で PreToolUse に matcher と command を書き同条目で onFailure block を設定。2.1.317 から明示 block のみ回调失败で tool を拦截。缺省や他値は fail-open や warn で hook_failure_gate は not_block_mode。

hooks settings:PreToolUse 条目 onFailure block。
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "./hooks/pre-bash.sh",
            "onFailure": "block"
          }
        ]
      }
    ]
  }
}

onFailure の大小文字混在や hooks 欠落なら schema が先に失敗し schema を返し、hook_failure_gate block 前に止める。形状错误を not_block_mode と混同しない。

hook 回调结果 JSON の hookName と exitCode の書き方

hook 回调完了後クライアントが结果 JSON を書く。hookName は PreToolUse 条目、onFailure は settings の block を echo、exitCode は脚本終了码、timedOut は timeout 杀死。permission が allow の Bash も hook 失败で block されうる。

hook 回调结果:hookName、onFailure、exitCode、timedOut。
{
  "hookName": "pre-bash.sh",
  "onFailure": "block",
  "exitCode": 2,
  "timedOut": false
}

exitCode は整数、timedOut は布尔必須。hookName 欠落や onFailure 形状错误なら hook_failure_gate は schema。onFailure が block でなければ not_block_mode。

hook 回调结果 JSON Schema:形状を通してから hook_failure_gate。
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "additionalProperties": false,
  "required": ["hookName", "onFailure", "exitCode", "timedOut"],
  "properties": {
    "hookName": { "type": "string", "minLength": 1 },
    "onFailure": { "type": "string", "enum": ["block", "continue"] },
    "exitCode": { "type": "integer" },
    "timedOut": { "type": "boolean" }
  }
}

hook 拦截前後の Bash tool 呼び出し JSON の照合

サンプル:permission policy で Bash allow、呼び出し JSON に tool Bash と command npm test。PreToolUse が exitCode 2 で onFailure block なら Bash 実行せず監査 JSON に decision blocked と reason hook_callback_failed。元 command と hookName を残し hook_failure_gate block 分支と照合。

hook 成功:Bash tool 呼び出し続行可。
{
  "tool": "Bash",
  "command": "npm test"
}
hook 失败 block:Bash 未実行。
{
  "hookName": "pre-bash.sh",
  "onFailure": "continue",
  "exitCode": 2,
  "timedOut": false
}

監査ログの decision blocked と hook_callback_failed の書き方

hook 回调失败で onFailure block のとき tool 監査 JSON に decision blocked、reason hook_callback_failed、hookName、非零 exitCode。timedOut true なら timeout フラグ可だが reason は hook_callback_failed。permission deny と hook block を同一 reason 枚举に混ぜない。

監査ログ:decision blocked、reason hook_callback_failed、hookName、exitCode。
{
  "tool": "Bash",
  "decision": "blocked",
  "reason": "hook_callback_failed",
  "hookName": "pre-bash.sh",
  "onFailure": "block",
  "exitCode": 2
}
ログまたは呼び出し現象hook_failure_gate 戻り運用対応
exitCode 0、timedOut false、onFailure blockallowtool 実行可。ログに hook_callback_failed 不要。
exitCode 非零、onFailure block、timedOut falseblockdecision blocked、reason hook_callback_failed、exitCode に合わせる。
onFailure が block 未設定または warnnot_block_modehook_callback_failed を書かず fail-open 旧报表と照合。
timedOut true かつ onFailure blocktimeout_blockログは hook_callback_failed のまま。SIEM は timeout_block を分離集計。

hook_failure_gate は schema と五业务分支をどう選ぶか

順序:hooks settings と回调结果 JSON Schema で onFailure と hookName、exitCode、timedOut を検証;onFailure が block でなければ not_block_mode;timedOut true かつ block なら timeout_block;exitCode 0 は allow;非零 exitCode かつ block は block;形状错误 schema。

block と timeout_block を hook_failed 一つに畳まない。レポートで not_block_mode fail-open、exitCode 失败 block、本当の timeout_block を分ける。

hook_failure_gate:schema、not_block_mode、allow、block、timeout_block。
def actual_type(data: object) -> str:
    if data is None:
        return "null"
    if isinstance(data, bool):
        return "boolean"
    if isinstance(data, list):
        return "array"
    if isinstance(data, int):
        return "integer"
    if isinstance(data, float):
        return "number"
    if isinstance(data, str):
        return "string"
    if isinstance(data, dict):
        return "object"
    raise TypeError(type(data))

def validate(data: object, schema: dict) -> list[str]:
    errors: list[str] = []
    if not isinstance(schema, dict):
        return errors
    types = schema.get("type")
    if isinstance(types, str):
        types = [types]
    actual = actual_type(data)
    if types and not any(t == actual or (t == "number" and actual == "integer") for t in types):
        errors.append("type")
    if "enum" in schema and not any(value == data for value in schema["enum"]):
        errors.append("enum")
    if isinstance(data, str) and "minLength" in schema and len(data) < schema["minLength"]:
        errors.append("minLength")
    if isinstance(data, dict) and schema.get("properties"):
        for key in schema.get("required") or []:
            if key not in data:
                errors.append(f"required:{key}")
        if schema.get("additionalProperties") is False:
            for key in data:
                if key not in schema["properties"]:
                    errors.append(f"additional:{key}")
        for key, sub in schema["properties"].items():
            if key in data and data[key] is not None:
                errors.extend(validate(data[key], sub))
    return errors

def hook_failure_gate(ctx: dict, schema: dict) -> str:
    if validate(ctx, schema):
        return "schema"
    mode = ctx.get("onFailure")
    if mode != "block":
        return "not_block_mode"
    if ctx.get("timedOut"):
        return "timeout_block"
    code = ctx.get("exitCode")
    if code == 0:
        return "allow"
    return "block"

JSONNote で hooks settings、回调结果、監査ログをどう検証するか

  1. 1
    Schema で hooks 形状を固定

    開く JSON Schema。1欄に hooks settings schema、2欄に PreToolUse と onFailure block サンプル。required や enum 誤りを先に表示し、形状错误で allow や block を返さない。

  2. 2
    フォーマットで tool 呼び出しを確認

    開く JSON フォーマット。Bash tool 呼び出し JSON を貼る。tool と command キーを確認し、hook_failure_gate が block か allow か照合する。

  3. 3
    Diff で allow と blocked 監査ログを比較

    開く JSON Diff。左に hook 成功 allow サンプル、右に decision blocked と reason hook_callback_failed サンプル。Diff で光る hookName が SIEM 规则の键行。

よくある質問

onFailure block と旧 fail-open の違いは?

旧版は hook 回调失败で stderr や警告の後 tool を続行。2.1.317 で settings に onFailure block を明示すると非零 exitCode や timeout で decision blocked と reason hook_callback_failed を書き tool をスキップ。block 未設定なら fail-open のまま hook_failure_gate は not_block_mode。

exitCode 2 と他の非零码をログでどう区別するか?

2.1.317 から block は exitCode が零かどうかで見る。監査 JSON は整数 exitCode をそのまま書く。SIEM は 2 と 1 や 127 を分けてもよいが hook_failure_gate block は非零なら同一。exitCode を failed 布尔に省略しない。

onFailure には block 以外に何があるか?

warn や缺省 fail-open があり、失败しても tool 実行。block のみ decision blocked。レポートで not_block_mode を fail-open 集計し warn を hook_callback_failed と誤記しない。

hook block と permission policy 层の関係は?

permission policy は tool 種別の allow deny ask を決め、hook は実行前脚本校验。policy が Bash allow でも PreToolUse 失败と onFailure block で拦截。JSON は分離保存し hook_failure_gate は hook 层のみ、policy allow は判定しない。

本篇は攻击や bypass 教程か?

いいえ。2.1.317 onFailure block の JSON 形状、hook_callback_failed 監査、hook_failure_gate 分岐の説明のみで、运维と合规の検証と SIEM 帰属を助ける。hook 失败や exitCode で管控を bypass する手順は書かない。

まとめ

Claude Code 2.1.317 は Agent SDK hook で onFailure block を支持し、回调失败時に監査 JSON に decision blocked、reason hook_callback_failed、hookName、exitCode を書く。hooks settings、回调结果、Bash 呼び出し、blocked 監査の四样本で hook_failure_gate を動かし permission allow だけを見ない。

結論:settings や回调 JSON が schema 不通 → schema。onFailure が block でなければ not_block_mode。exitCode 0 → allow。非零 exitCode かつ block → block。timedOut true かつ block → timeout_block。block と timeout_block の監査は decision blocked、reason hook_callback_failed、hookName、exitCode に合わせる。

次:Schema で hooks settings と回调结果を固定し、Bash 呼び出しをフォーマットで見て、allow と blocked 監査ログを Diff し、hook_failure_gate 戻り値をレポートで分ける。

ブログへ戻る