Blog • Claude Code / Agent SDK
Nach Upgrade auf Claude Code 2.1.317 mit Agent SDK hook onFailure block: wie blockierte Hook-Callbacks in JSON-Logs festhalten?
Am 3. November 2026 lieferte Anthropic Claude Code 2.1.317. Agent SDK hook callbacks ergänzen onFailure block: bei non-zero Exit oder Timeout von PreToolUse-Hooks kein fail-open mehr, tool-Aktion wird blockiert und audit JSON trägt blocked.
Hook-Callback-Ergebnis-JSON braucht hookName, onFailure block, exitCode, timedOut; Audit-JSON nach Block: decision blocked, reason hook_callback_failed, hookName, exitCode. hook_failure_gate spiegelt schema, not_block_mode, allow, block, timeout_block statt Callback-Fehler als permission policy deny.
Allow- und deny-Queue in Agent permission policy; Managed Agents auto-Evaluationskontext in Managed Agents auto-Evaluation; Session-Workflow-JSON in Claude Code workflow. Dieser Artikel behandelt nur 2.1.317 onFailure block, hooks settings und Callback-Ergebnis-JSON, Bash-Beispiel, hook_callback_failed Audit-Felder sowie hook_failure_gate-Verzweigung.
- PreToolUse-Einträge in hooks settings brauchen onFailure block für tool-Block bei Callback-Fehler; fehlt block → hook_failure_gate not_block_mode, kein reason hook_callback_failed.
- Hook-Callback-Ergebnis-JSON braucht hookName, onFailure, integer exitCode, boolean timedOut; exitCode 0 und timedOut false → allow, non-zero exitCode mit onFailure block → block.
- Audit-Logs im block-Zweig: decision blocked, reason hook_callback_failed, hookName, exitCode; SIEM aggregiert nach hookName, nicht permission policy deny reasons.
- timedOut true und onFailure block → hook_failure_gate timeout_block; schlechte Form in settings oder Callback-JSON → schema vor Block-Logik.
Zuerst dies: 2.1.317 ändert block-Semantik bei Hook-Callback-Fehlern und hook_callback_failed Audit-Felder; allow- oder deny-Tabellen der permission policy werden nicht neu geschrieben. Unten: Changelog, hooks settings JSON, Callback-Ergebnis-JSON, Bash-Beispiel, Audit-Logs und Tabelle, hook_failure_gate-Quelltext, Formprüfung in JSONNote.
Wie blockiert 2.1.317 statt fail-open bei Hook-Callback-Fehler
Änderungen stehen in Claude Code changelog, Tag-Seite Release v2.1.317. Gegenüber früherem Agent SDK hook-Verhalten fällt onFailure block auf: PreToolUse-Hooks bei non-zero Exit oder Timeout blockieren die tool-Aktion statt nur zu warnen und fortzufahren.
Block nach Hook-Callback, vor tool-Ausführung. Audit-JSON: decision blocked, reason hook_callback_failed, hookName, exitCode für SIEM-Attribution zum fehlgeschlagenen Hook statt generischem tool denied.
Wie schreibt man PreToolUse und onFailure block in hooks settings JSON
Unter hooks in User- oder Projekt-Settings PreToolUse mit matcher und command konfigurieren und onFailure block setzen. Ab 2.1.317 blockiert nur explizites block bei Callback-Fehler; Default oder andere Werte → fail-open oder warn, hook_failure_gate not_block_mode.
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "./hooks/pre-bash.sh",
"onFailure": "block"
}
]
}
]
}
}
Falsche Schreibweise von onFailure oder fehlendes hooks → schema zuerst, bevor hook_failure_gate blockt. Formfehler nicht als not_block_mode werten.
Wie hookName und exitCode im Hook-Callback-Ergebnis-JSON stehen
Nach Hook-Callback schreibt der Client Ergebnis-JSON: hookName benennt PreToolUse-Eintrag, onFailure echo block aus settings, exitCode ist Skript-Exit, timedOut markiert Timeout-Kill. Bash trotz permission allow kann bei Hook-Fehler blockiert werden.
{
"hookName": "pre-bash.sh",
"onFailure": "block",
"exitCode": 2,
"timedOut": false
}
exitCode integer, timedOut boolean; fehlendes hookName oder schlechte onFailure-Form → schema zuerst. onFailure nicht 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" }
}
}
Wie Bash tool call JSON vor und nach Hook-Block aussieht
Beispiel: permission policy erlaubt Bash; Call-JSON tool Bash und command npm test. PreToolUse exitCode 2 mit onFailure block → kein Bash, Audit-JSON decision blocked und reason hook_callback_failed. Original command und hookName für hook_failure_gate block.
{
"tool": "Bash",
"command": "npm test"
}
{
"hookName": "pre-bash.sh",
"onFailure": "continue",
"exitCode": 2,
"timedOut": false
}
Wie decision blocked und hook_callback_failed in Audit-Logs stehen
Hook-Callback-Fehler mit onFailure block: tool Audit-JSON decision blocked, reason hook_callback_failed, hookName, non-zero exitCode; timedOut true optional timeout-Flag, reason bleibt hook_callback_failed. permission deny und hook block nicht in einer reason-Enum mischen.
{
"tool": "Bash",
"decision": "blocked",
"reason": "hook_callback_failed",
"hookName": "pre-bash.sh",
"onFailure": "block",
"exitCode": 2
}
| Log- oder Aufrufsignal | hook_failure_gate liefert | Operator-Aktion |
|---|---|---|
| exitCode 0, timedOut false, onFailure block | allow | Tool darf laufen; kein hook_callback_failed im Log. |
| Non-zero exitCode, onFailure block, timedOut false | block | An decision blocked, reason hook_callback_failed, exitCode anpassen. |
| onFailure nicht block oder Wert warn | not_block_mode | Kein hook_callback_failed; mit legacy fail-open Reports vergleichen. |
| timedOut true und onFailure block | timeout_block | Logs behalten hook_callback_failed; SIEM zählt timeout_block getrennt. |
Wie hook_failure_gate zwischen schema und fünf Fachzweigen wählt
Reihenfolge: Schema für hooks settings und Callback-Ergebnis mit onFailure, hookName, exitCode, timedOut; onFailure nicht block → not_block_mode; timedOut true mit block → timeout_block; exitCode 0 → allow; non-zero exitCode mit block → block; Formfehler → schema.
block und timeout_block nicht zu einem hook_failed-Bit zusammenlegen. Getrennt zählen für not_block_mode fail-open, exitCode-Block und echtes 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"
Wie validiert man hooks settings, Callback-Ergebnisse und Audit-Logs in JSONNote
- 1Hooks-Form per Schema fixieren
Öffnen Sie JSON Schema. Hooks-settings-Schema ins erste Feld, PreToolUse und onFailure block ins zweite. required oder enum zuerst; bei schlechter Form kein allow oder block von hook_failure_gate.
- 2Format für tool-Aufrufe
Öffnen Sie JSON formatieren, Bash tool call JSON einfügen. tool und command prüfen, dann ob hook_failure_gate block oder allow liefern soll.
- 3Diff: allow vs blocked Audit-Logs
Öffnen Sie JSON Diff. Links Hook-erfolg allow, rechts decision blocked und reason hook_callback_failed. Hervorgehobenes hookName ist die SIEM-Schlüsselzeile.
Häufige Fragen
Worin unterscheidet sich onFailure block vom alten fail-open?
Legacy loggte Hook-Fehler und fuhr mit tool fort. Ab 2.1.317 mit onFailure block in settings schreiben non-zero exitCode oder timeout decision blocked und reason hook_callback_failed und überspringen tool. Ohne block bleibt fail-open, hook_failure_gate not_block_mode.
Wie unterscheiden Logs Exit-Code 2 von anderen non-zero Codes?
Ab 2.1.317 hängt block daran, ob exitCode null ist, nicht nur 2. Audit-JSON speichert integer exitCode unverändert; SIEM darf 2 von 1 oder 127 trennen, hook_failure_gate block behandelt jeden non-zero gleich. exitCode nicht zu boolean failed verkürzen.
Welche onFailure-Werte gibt es neben block?
Üblich warn oder Default fail-open: Fehler warnt, tool läuft weiter. Nur block → decision blocked. not_block_mode für fail-open zählen, warn nicht als hook_callback_failed loggen.
Wie hängt hook block mit der permission-policy-Schicht zusammen?
permission policy steuert allow deny ask pro tool; hooks prüfen per Skript vor Ausführung. Auch policy allow Bash blockiert fehlgeschlagenes PreToolUse mit onFailure block. JSON getrennt; hook_failure_gate nur Hook-Schicht, kein policy allow.
Enthält dieser Artikel Angriffs- oder Bypass-Tutorials?
Nein. Der Artikel erklärt nur JSON-Formen onFailure block 2.1.317, hook_callback_failed Audit-Felder und hook_failure_gate-Zweige für Betrieb und Compliance. Keine Schritte zum Umgehen von Controls via Hook-Fehler oder exitCode.
Fazit
Claude Code 2.1.317 unterstützt onFailure block für Agent SDK hooks und schreibt bei Callback-Fehlern decision blocked, reason hook_callback_failed, hookName und exitCode ins Audit-JSON. hook_failure_gate mit hooks settings, Callback-Ergebnissen, Bash-Aufrufen und blocked Audit füttern, nicht nur permission allow.
Entscheidung: settings oder Callback-JSON scheitert schema → schema; onFailure nicht block → not_block_mode; exitCode 0 → allow; non-zero exitCode mit block → block; timedOut true mit block → timeout_block; block und timeout_block Audit passen zu decision blocked, reason hook_callback_failed, hookName, exitCode.
Als Nächstes: hooks settings und Callback-Ergebnisse per Schema, Format für Bash-Aufrufe, Diff allow vs blocked Audit-Logs, hook_failure_gate-Rückgaben getrennt berichten.