ブログ • 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 分岐のみを書く。
- hooks settings の PreToolUse 等は onFailure block を宣言しないと回调失败で tool を拦截しない。未宣言や block 以外なら hook_failure_gate は not_block_mode を返し reason hook_callback_failed を書かない。
- hook 回调结果 JSON に hookName、onFailure、整数 exitCode、布尔 timedOut が要る。exitCode 0 かつ timedOut false なら allow、非零 exitCode で onFailure block なら block。
- block 分支の監査ログに decision blocked、reason hook_callback_failed、hookName、exitCode。SIEM は hookName で集計し permission policy の deny reason と混ぜない。
- timedOut true かつ onFailure block なら hook_failure_gate は timeout_block。settings や回调结果 JSON の形状错误なら block 判定前に schema。
先にこれだけ: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": {
"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 されうる。
{
"hookName": "pre-bash.sh",
"onFailure": "block",
"exitCode": 2,
"timedOut": false
}
exitCode は整数、timedOut は布尔必須。hookName 欠落や onFailure 形状错误なら hook_failure_gate は schema。onFailure が block でなければ not_block_mode。
{
"$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 分支と照合。
{
"tool": "Bash",
"command": "npm test"
}
{
"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 枚举に混ぜない。
{
"tool": "Bash",
"decision": "blocked",
"reason": "hook_callback_failed",
"hookName": "pre-bash.sh",
"onFailure": "block",
"exitCode": 2
}
| ログまたは呼び出し現象 | hook_failure_gate 戻り | 運用対応 |
|---|---|---|
| exitCode 0、timedOut false、onFailure block | allow | tool 実行可。ログに hook_callback_failed 不要。 |
| exitCode 非零、onFailure block、timedOut false | block | decision blocked、reason hook_callback_failed、exitCode に合わせる。 |
| onFailure が block 未設定または warn | not_block_mode | hook_callback_failed を書かず fail-open 旧报表と照合。 |
| timedOut true かつ onFailure block | timeout_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 を分ける。
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、回调结果、監査ログをどう検証するか
- 1Schema で hooks 形状を固定
開く JSON Schema。1欄に hooks settings schema、2欄に PreToolUse と onFailure block サンプル。required や enum 誤りを先に表示し、形状错误で allow や block を返さない。
- 2フォーマットで tool 呼び出しを確認
開く JSON フォーマット。Bash tool 呼び出し JSON を貼る。tool と command キーを確認し、hook_failure_gate が block か allow か照合する。
- 3Diff で 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 戻り値をレポートで分ける。