
The Claude Code Changelog· Folge 177
Failing Closed with Agent SDK Hooks in Claude Code 2.1.317
Dienstag, 3. November 2026 · 5 min
Kapitelklicken springt direkt hin
Shownotes
Learn how Claude Code version 2.1.317 introduces onFailure: "block" for programmatic Agent SDK hook callbacks, preventing unattended agents from failing open on unexpected errors. We also cover protections against account email leakage in tools, isolated transcripts for nested headless sessions, and full-file re-reading behavior.
Transkriptvom Podcast bereitgestellt · Zeitmarken springen hin
Right, grab a coffee, because today's one is about what happens when your safety check falls over. This is The Claude Code Changelog, brought to you by Jellypod AI. Version 2.1.317 landed on November 3rd, 2026, with 87 changes across security, hooks, and session orchestration. We're picking one of them, and it closes a gap that could bite anyone running agents unattended.
Yeah. Back in version 2.1.295 we covered onFailure block for JSON configured command and HTTP hooks. That made those hooks fail closed. But Agent SDK hook callbacks, the programmatic ones you write in code, were left out. Until now they failed open by default. So if your callback crashed, timed out, or threw an unhandled error while checking a permission or verifying a tool call, Claude Code let the tool run anyway.
Which is a bit like a bouncer who falls asleep and the club just opens the doors. If you're building automated agents or headless wrappers on the Agent SDK, your guardrail was only as good as its uptime. A flaky network call inside your callback, a null you didn't expect, and a potentially destructive action slips through without anyone saying yes.
So here's the fix. In 2.1.317, when you configure a hook handler programmatically, say a PreToolUse or PermissionRequest callback, you explicitly supply onFailure set to block in the hook callback's configuration options. Once that's on, any thrown error or failed callback halts the tool call, and a blocking error is surfaced back to the model instead of the tool proceeding.
I'd check the SDK reference for exactly where that option sits in your language's types, but the value is block, and you set it per hook. Practical example. Say your PreToolUse callback looks up a policy service before letting Bash commands through. Before, if that service timed out, the callback failed, and the command ran.
With onFailure block, the same timeout stops the command, and the model gets told it was blocked. It can then explain, retry, or pick a safer route. That's what you want from a guardrail, deny by default when you can't confirm. Now, the caveats. First, only use this on events that can actually block.
The brief names PreToolUse, PermissionRequest, UserPromptSubmit, and PreCompact. If you set it on a post execution hook like PostToolUse, it does nothing, because the action already happened. Second, watch your timeouts. A blocking callback that hangs will hold up session progress until it finally fails, so set reasonable limits on anything that calls out over the network.
And third one's for the CI crowd. In a headless pipeline or automated runner, a blocking failure will abort the turn unless your agent is set up to catch and recover from the denial. So test the unhappy path on purpose. Break your callback, see what the run does, and make sure that's the outcome you wanted at three in the morning.
Okay, a few smaller things from the same release. One is a security one. There's now an interactive confirmation when a web tool, so WebFetch, WebSearch, or WebBrowser, or a shell tool, so Bash, Monitor, PowerShell, or Tmux, is about to send your signed in account email address over the network. It matches both the raw string and the URL encoded version, so it stops silent leakage.
Next, nested headless sessions. By default, when you run claude with the p flag inside a cloud or self hosted runner session, it now gets its own session ID and its own transcript, instead of sharing and overwriting the parent's. If you actually depended on the old shared transcript behavior, set CLAUDE_CODE_DISABLE_NESTED_SESSION_ID to 1 on your self hosted runners.
Also, the old file unchanged since your last Read stub is gone. Reading an unchanged file again now returns the full text. That's more accurate, but you may see slightly higher token use on repeat reads. And subagents or teammates assigned a different model from the main conversation now use that model's saved effort level, or its default, instead of inheriting the parent session's effort.
One for admins too. The Claude apps gateway admin API has a new GET endpoint at /v1/organizations/analytics/cost, which aggregates spend across date ranges, developers, and IdP groups. So the action item is simple. Audit your Agent SDK code for blocking hook callbacks, add onFailure block to the ones that guard anything destructive, then deliberately make one fail and watch what happens.
That's the whole job, and it's worth doing before your next unattended run.