Plugin updater loses execute permission on cached hook scripts
Expected
Hook scripts referenced in a plugin's hooks.json are executable after plugin install/update, regardless of how they were packaged or delivered.
Actual
Scripts under ~/.claude/plugins/cache/<marketplace>/<plugin>/unknown/hooks-handlers/ are mode 644 after install. This produces two bare errors on every launch:
SessionStart:startup hook error
SessionStart:startup hook error
Running the script manually confirms the cause:
$ ~/.claude/plugins/cache/claude-plugins-official/learning-output-style/unknown/hooks-handlers/session-start.sh
bash: .../session-start.sh: Permission denied
The marketplace source files are also 644, so the cache is faithfully copying what it receives. An older cached version (6b70f99f769f) has the correct 755 permissions, suggesting a difference in how these versions were populated.
Affected plugins (both from claude-plugins-official):
learning-output-styleexplanatory-output-style
Workaround
chmod +x ~/.claude/plugins/cache/claude-plugins-official/learning-output-style/unknown/hooks-handlers/session-start.sh
chmod +x ~/.claude/plugins/cache/claude-plugins-official/explanatory-output-style/unknown/hooks-handlers/session-start.sh
Resolves the error until the next plugin update re-caches the files.
Note: unknown/ cache versions are also affected by unexpanded ${CLAUDE_PLUGIN_ROOT} templates (see #24529). The permissions bug reported here is independent. Both must be fixed for plugin hooks to work.
Environment
Claude Code: 2.1.84, 2.1.85
Platforms: Linux (WSL2, ext4), macOS (Intel, macOS 13)
Plugin version field: "unknown"
umask: 0022
Notes
- Reproduced independently on both Linux (WSL2) and macOS, ruling out filesystem-specific behavior
- Reproduced on both v2.1.84 and v2.1.85
- Standard umask (
0022) means newly written files default to644; the runtime would need an explicitchmodstep - The error message ("SessionStart:startup hook error") does not identify which hook failed or the underlying cause. Including the script path would make this trivial to diagnose
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗