Plugin updater loses execute permission on cached hook scripts

Resolved 💬 3 comments Opened Mar 27, 2026 by traylorre Closed Mar 27, 2026

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-style
  • explanatory-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 to 644; the runtime would need an explicit chmod step
  • 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

View original on GitHub ↗

This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗