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.

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 settings: PreToolUse-Eintrag onFailure block.
{
  "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.

Hook-Callback-Ergebnis: hookName, onFailure, exitCode, timedOut.
{
  "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.

Hook-Callback-Ergebnis-JSON-Schema: Form vor 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" }
  }
}

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.

Hook erfolgreich: Bash tool call darf fortgesetzt werden.
{
  "tool": "Bash",
  "command": "npm test"
}
Hook fehlgeschlagen block: Bash lief nicht.
{
  "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.

Audit-Log: decision blocked, reason hook_callback_failed, hookName, exitCode.
{
  "tool": "Bash",
  "decision": "blocked",
  "reason": "hook_callback_failed",
  "hookName": "pre-bash.sh",
  "onFailure": "block",
  "exitCode": 2
}
Log- oder Aufrufsignalhook_failure_gate liefertOperator-Aktion
exitCode 0, timedOut false, onFailure blockallowTool darf laufen; kein hook_callback_failed im Log.
Non-zero exitCode, onFailure block, timedOut falseblockAn decision blocked, reason hook_callback_failed, exitCode anpassen.
onFailure nicht block oder Wert warnnot_block_modeKein hook_callback_failed; mit legacy fail-open Reports vergleichen.
timedOut true und onFailure blocktimeout_blockLogs 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.

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"

Wie validiert man hooks settings, Callback-Ergebnisse und Audit-Logs in JSONNote

  1. 1
    Hooks-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.

  2. 2
    Format 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.

  3. 3
    Diff: 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.

Zurück zum Blog