[BUG] A hooks-shaped section under another top-level settings key silently stops every hook in the file
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report
- [ ] I am using the latest version of Claude Code: not confirmed; the version is below
What's Wrong?
In the desktop app, a project's .claude/settings.json that holds a valid hooks section and another top-level key holding a hooks-shaped object makes the session run no hook from that file, the valid ones under hooks included. Examples of such a key: "disabledHooks": { "PreToolUse": [ ... ] }, or "_hooks": { "PreToolUse": [ ... ] }.
Nothing tells anyone. The user saw no settings error notice in the app, and nothing reached the agent. The documentation says a schema error in a project settings file brings "a settings error notice".
A natural way to meet it is parking hooks under another key to switch them off for a while. Every hook in the file then stops, guards included, silently.
Measured the same way, these were ignored, with the file's hooks still running, so only a hooks-shaped section under a key other than hooks had the effect:
- top-level keys holding strings:
"_sample": "...","_hooks": "..." - top-level keys holding a plain object:
"probeNote": { ... },"_hooks": { "probe": 1 } - an unknown event name under
hooks:"_PreToolUse": [ ... ] - an extra key inside a matcher entry, or inside a hook object
What Should Happen?
Either the extra key is ignored like the other unknown keys, or the file is rejected with the settings error notice the documentation describes, so the user knows their hooks are off.
Error Messages/Logs
None, which is the problem: no notice to the user and no message to the agent.
Steps to Reproduce
- A project whose
.claude/settings.jsonhas a workingPreToolUsehook, such as one that refuses a command or appends a line to a log file. - Mid-session, add a second top-level key to that file:
"disabledHooks": {
"PreToolUse": [
{ "matcher": "Read", "hooks": [ { "type": "command", "command": "node", "args": ["probe.mjs", "parked"] } ] }
]
}
- Make any tool call. The working hook no longer runs. Remove the key, and it runs again from the next call.
How it was told apart from a file not yet reloaded: each round held one control hook that had to fire on Read, and a guard hook that refuses a particular shell command. A file not yet reloaded keeps the old hooks, so the guard still refuses. A file reloaded with no hook running lets the command through.
Claude Model
claude-opus-5-5
Is this a regression?
I don't know.
Claude Code Version
Claude desktop app 2.16120.0, the Code tab; Agent SDK 0.3.284; entrypoint claude-desktop. Not tested in the CLI.
Platform
Anthropic API
Operating System
Windows 11 Pro 10.0.26200
Found and written up by Claude Code, in a session that ran the test with its user, 2026-10-01.