Bug: Spaces in ${CLAUDE_PLUGIN_ROOT} break hook commands
Preflight Checklist
- [x] I'm on the latest version of Claude Code
- [x] I've searched existing issues for duplicates
- [x] I've read the troubleshooting guide
What's Wrong?
When hooks.json commands reference ${CLAUDE_PLUGIN_ROOT} and the expanded path contains spaces, the hook command fails because Claude Code passes the expanded string to /bin/sh -c without quoting. The shell splits the path at space boundaries.
This is not a duplicate of #24529 (variable not being set). Here the variable IS set and expanded — the expanded value just isn't properly quoted.
What Should Happen?
Hook commands using ${CLAUDE_PLUGIN_ROOT} should work regardless of whether the plugin installation path contains spaces. Claude Code should either:
- Quote the expanded variable when passing to
/bin/sh -c, or - Use
execFile-style invocation that avoids shell word splitting
Error Messages/Logs
/bin/sh: /Users/someone/My: No such file or directory
(The actual path was /Users/someone/My Projects/plugin-name/hooks/run.sh but the shell split at the space.)
Steps to Reproduce
- Create a test plugin in a directory with a space in the path:
mkdir -p "/tmp/My Plugins/test-plugin/hooks"
mkdir -p "/tmp/My Plugins/test-plugin/.claude-plugin"
cat > "/tmp/My Plugins/test-plugin/.claude-plugin/plugin.json" << 'PJSON'
{"name": "test-spaces", "version": "1.0.0", "description": "Repro for spaces bug"}
PJSON
cat > "/tmp/My Plugins/test-plugin/hooks/hooks.json" << 'HJSON'
{
"hooks": {
"PostToolUse": [
{
"matcher": "*",
"hooks": [{"type": "command", "command": "${CLAUDE_PLUGIN_ROOT}/hooks/test-hook.sh"}]
}
]
}
}
HJSON
cat > "/tmp/My Plugins/test-plugin/hooks/test-hook.sh" << 'HOOK'
#!/bin/bash
echo "HOOK EXECUTED" > /tmp/hook-ran.txt
cat
HOOK
chmod +x "/tmp/My Plugins/test-plugin/hooks/test-hook.sh"
- Run Claude Code with the plugin:
claude --plugin-dir "/tmp/My Plugins/test-plugin" --print "read the file /etc/hostname"
- Check if the hook ran:
cat /tmp/hook-ran.txt 2>&1 || echo "Hook never ran — bug confirmed"
- Compare with a no-spaces path (identical plugin at
/tmp/MyPlugins/test-plugin) — works fine.
Workaround
Escape quotes in hooks.json:
"command": "\"${CLAUDE_PLUGIN_ROOT}/hooks/run.sh\" args"
Claude Model
Sonnet
Is this a regression?
I don't know
Claude Code Version
2.1.73
Platform
Anthropic API
Operating System
macOS
Terminal/Shell
Terminal.app
Additional Information
This affects all platforms since the expansion + /bin/sh -c pattern is platform-independent. Any user whose home directory or plugin install path contains a space will hit this.
This issue has 7 comments on GitHub. Read the full discussion on GitHub ↗