Shell snapshot PATH export contains literal $PATH — system directories lost
Bug Description
Claude Code's shell snapshot mechanism stores the PATH with a literal $PATH reference that is not properly expanded when loaded back. This causes critical system directories (/usr/bin, /bin, /usr/sbin, /sbin) to be missing from the Bash tool's PATH environment.
Environment
- Claude Code version: 2.1.71 (native binary, macOS arm64)
- OS: macOS (Apple Silicon)
- Shell: zsh
- Installation: Native (
~/.local/share/claude/versions/)
Steps to Reproduce
- Install Claude Code natively on macOS
- Start a Claude Code session — a shell snapshot is generated at
~/.claude/shell-snapshots/snapshot-zsh-*.sh - Run any Bash tool command:
echo $PATH - Observe the PATH contains a literal
$PATHstring instead of expanded system paths
Observed Behavior
The shell snapshot's last line stores:
export PATH=$PATH\:/Users/<user>/.nvm/versions/node/v22.18.0/bin\:/opt/homebrew/bin\:/usr/local/bin
When Claude Code loads this snapshot, $PATH is treated as a literal string rather than being shell-expanded. The resulting PATH in the Bash tool is:
/Users/<user>/.local/bin:$PATH:/Users/<user>/.nvm/versions/node/v22.18.0/bin:/opt/homebrew/bin:/usr/local/bin
Note the literal $PATH in the middle. System directories from /etc/paths (/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin) are never included.
Expected Behavior
The PATH should include macOS system directories (/usr/bin, /bin, etc.) sourced from /etc/paths. Either:
- The snapshot should store the fully-resolved PATH (not a
$PATHreference), or - The snapshot loader should properly shell-expand
$PATHbefore setting the environment variable
Impact
git submodulefails because its internal shell scripts callbasename,sed,uname(all in/usr/bin):
````
/opt/homebrew/opt/git/libexec/git-core/git-submodule: line 7: basename: command not found
/opt/homebrew/opt/git/libexec/git-core/git-sh-setup: line 77: sed: command not found
/opt/homebrew/opt/git/libexec/git-core/git-sh-setup: line 292: uname: command not found
- Plugin installation fails for any plugin whose source uses git submodules (e.g.,
figma@claude-plugins-official) - Direct shell commands like
ls,cat,grep,head,tailare not found (though Claude Code's built-in Read/Grep tools are unaffected) - This has been present since the first snapshot (v2.1.20, Jan 27 2026) and persists across all 13 snapshots through v2.1.71
Workaround
Add an explicit PATH to ~/.claude/settings.json:
{
"env": {
"PATH": "/usr/bin:/bin:/usr/sbin:/sbin:/opt/homebrew/bin:/opt/homebrew/sbin:/usr/local/bin:/Users/<user>/.local/bin"
}
}
This is fragile — it requires manual updates when tools like nvm change Node versions.
Root Cause Analysis
The snapshot file (~/.claude/shell-snapshots/snapshot-zsh-*.sh) uses escaped colons (\:) in the PATH export line, suggesting the snapshot generator escapes special characters. However, the $PATH variable reference is preserved as-is. When the snapshot loader processes this line, it appears to unescape \: → : but treats $PATH as a literal string rather than performing variable substitution.
A fresh macOS login shell correctly resolves PATH via /etc/paths → path_helper(8) → .zprofile → .zshrc, but the snapshot's export PATH= overrides the fully-resolved PATH with the broken version.
This issue has 5 comments on GitHub. Read the full discussion on GitHub ↗