security-guidance plugin hook fails with ENOENT in local-agent-mode-sessions staging, causing infinite retry/notification loop
Summary
The security-guidance (v2.0.7, official plugin) hook security_reminder_hook.py intermittently fails with ENOENT when invoked from its per-session staging path, and the failure retries indefinitely rather than surfacing once — flooding the session with repeated "Idle." / "(no change)" notification turns and making the session effectively unusable. Restarting the Claude Code desktop app does not clear the loop.
Environment
- Windows 11 Home Single Language 10.0.26200
- Claude Code desktop app,
autoUpdatesChannel: "latest" - Plugin:
security-guidance@claude-plugins-official, marketplaceclaude-plugins-official, cached version2.0.7 - Plugin id referenced in the failing path:
plugin_01YBNfaNwQztYsnUydt8m47G
Exact error (repeated, verbatim)
C:\Users\<user>\AppData\Local\Python\pythoncore-3.14-64\python.exe: can't open file 'C:\Users\<user>\AppData\Roaming\Claude\local-agent-mode-sessions\<session-id>\<subsession-id>\rpm\plugin_01YBNfaNwQztYsnUydt8m47G\hooks\security_reminder_hook.py': [Errno 2] No such file or directory
Delivered repeatedly as background <task-notification> events (summary: "Background security review found issues"), each turn, across multiple concurrent sessions on the same project simultaneously.
What we verified before filing
- The plugin's real install is intact:
~/.claude/plugins/cache/claude-plugins-official/security-guidance/2.0.7/hooks/security_reminder_hook.pyexists and is well-formed. - The per-session staged manifest (
.../rpm/manifest.json) correctly listsplugin_01YBNfaNwQztYsnUydt8m47Gassecurity-guidance. - At the moment we checked, the staged copy at the exact failing path (
.../rpm/plugin_01YBNfaNwQztYsnUydt8m47G/hooks/security_reminder_hook.py) did exist, fully staged, matching the source file — yet the same session kept throwing the identical ENOENT error on the next several turns regardless. This points to a race condition in how/when the hook is invoked relative to per-session plugin staging, not a corrupted or missing install. - Restarting the Claude Code app three times did not stop the loop (the
rpm/staging folder was confirmed regenerated fresh each time, same failure reproduced immediately). - It affected multiple concurrent session windows on the same project at once, all independently stuck in the same repeat pattern (some reaching 45+ repeats), each showing a "stop" control in its own window but no way to prevent the loop from resuming.
Workaround that resolved it
Disabling / removing the security-guidance plugin (Settings → Plugins, or setting "security-guidance@claude-plugins-official": false in ~/.claude/settings.json) followed by an app restart stopped the loop for good. No other plugin was involved.
Suggested fix direction
- Whatever triggers
security_reminder_hook.pyper-turn should tolerate the plugin's per-sessionrpm/staging not yet being complete (retry-with-backoff or wait-for-stage, rather than immediate hard failure), and should not re-fire on every subsequent turn once it has already failed for that turn. - The failure should not present to the user as a synthetic
<task-notification>"Background security review found issues" — this framing made a plugin infrastructure bug look like an actual security finding, and it repeated across every turn/session, effectively making the session unusable and requiring a plugin uninstall to work around.
Showing cached comments. Read the full discussion on GitHub ↗
3 Comments
Corroborating this from a separate environment — same plugin ID (plugin_01YBNfaNwQztYsnUydt8m47G), same hook (security_reminder_hook.py), same infinite-retry-no-backoff pattern, same misleading "Background security review found issues" notification framing.
Differences from the original report, likely just environment variance rather than a different bug: our Python interpreter was the Microsoft Store app-execution-alias stub (AppData\Local\Microsoft\WindowsApps\python3.13.exe) rather than a pythoncore install, and our local ~/.claude/settings.json / per-session rpm/manifest.json referenced marketplace name knowledge-work-plugins rather than claude-plugins-official for the same plugin ID.
One additional data point: we saw the hook fire as a synchronous PostToolUse:Edit hook failure (not just the periodic background notification), immediately after an Edit tool call — so it's not confined to whatever triggers the periodic "security review" notification; it's wired into normal tool-call hook dispatch too.
We also independently reproduced the fix: adding explicit "security-guidance@<marketplace>": false entries to enabledPlugins in ~/.claude/settings.json, followed by a restart, per the original report's workaround.
Update from our side: we've now tried every local-config lever suggested here, in order —
"security-guidance@...": false in enabledPlugins — did not stop the loop
Fully removing the enabledPlugins entries entirely — did not stop the loop
Fully killing all claude.exe processes via Task Manager, a full system reboot, and a fresh app start — the identical ENOENT/"Background security review found issues" loop is still firing afterward
This rules out local settings.json state and even a full process/OS restart as a fix, and reinforces the earlier point that the failing per-session rpm/ staging path isn't something a client-side restart clears. At this point it looks like it'd need a fix shipped by Anthropic rather than anything actionable locally.
Related reports: #95727 and #94634.
I reproduced a narrower failure in the public launcher: sg-python.sh executes Python directly, so a missing script produces interpreter exit 2, although no review ran. The Stop hook enables asyncRewake, whose documented wake-up condition is exit 2. Its fixed summary says “Background security review found issues”. The Python stop_hook_active guard cannot run when that script is missing.
Minimal reproduction from the repository root, with Python 3 installed:
A minimal mitigation is a script-path existence check before interpreter dispatch:
All six current hooks.json invocations pass a script path first. This preserves interpreter-option passthrough and directory execution; it does not remap legitimate review exit 2.
In a temporary copy on macOS, ten controlled comparisons passed: missing script, script exits 0/1/2, two
-ccases,-m,-, no-argument stdin, and directory execution. Paths containing spaces were included. Only the missing-script case changed (2→1); the controlled finding stub retained exit 2, and existing outputs were unchanged. No security scan or model call ran.This validates the launcher mitigation, not the full Desktop loop. Windows/Git Bash remain untested. It does not repair staging, address replayed notifications, or eliminate the check-to-exec race.
Analysis and local validation were prepared with AI assistance.