[BUG] Shell snapshots capture interactive functions without dependencies, breaking cd and other commands

Resolved 💬 3 comments Opened Oct 16, 2025 by mishaal79 Closed Oct 19, 2025

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet
  • [x] This is a single bug report (please file separate reports for different bugs)
  • [x] I am using the latest version of Claude Code

What's Wrong?

Shell snapshots capture interactive shell function definitions (from .zshrc) but source them in non-interactive contexts where their dependencies don't exist. This breaks commands like cd for users with zoxide and any other shell functions that depend on tools initialized in .zshrc.

Error example:

cd:1: command not found: __zoxide_z

The root cause is an architectural issue: snapshots capture function references (e.g., cd() { __zoxide_z "$@" }) without capturing function dependencies (the __zoxide_z implementation itself).

This affects:

  • Users with zoxide (2.5M+ installs)
  • Users with fzf keybindings
  • Users with Oh My Zsh, zinit, or similar frameworks
  • Anyone with custom shell functions in .zshrc

What Should Happen?

When Claude Code sources shell snapshots in non-interactive contexts, either:

Option A (Ideal): Resolve and capture all function dependencies so they work in non-interactive shells

Option B (Acceptable): Don't capture functions that override builtins or have external dependencies

Option C (Minimum): Fail early with a clear error message explaining the missing dependency and suggesting workarounds

Error Messages/Logs

# Running Bash tool command
cd /tmp

# Error output
cd:1: command not found: __zoxide_z

# Verification
$ type cd
cd is a shell function from /Users/username/.claude/shell-snapshots/snapshot-zsh-1760588587940-0rl83n.sh

$ type __zoxide_z
zsh: command not found: __zoxide_z

Steps to Reproduce

  1. Install zoxide:

```bash
# macOS
brew install zoxide

# Linux
curl -sS https://raw.githubusercontent.com/ajeetdsouza/zoxide/main/install.sh | bash
```

  1. Configure .zshrc (add this line):

``bash
# In ~/.zshrc
eval "$(zoxide init zsh --cmd cd)"
``

  1. Start new terminal to load configuration:

``bash
exec zsh
``

  1. Verify cd override in interactive shell:

```bash
type cd
# Output: cd is a shell function

type __zoxide_z
# Output: __zoxide_z is a shell function (shows definition)
```

  1. Start Claude Code and run Bash tool command:

``bash
cd /tmp
``

  1. Observe error:

``
cd:1: command not found: __zoxide_z
``

Technical Root Cause

Snapshot capture flow:

  1. Captures shell state from interactive shell (where .zshrc is loaded)
  2. Serializes ~6,074 lines with 146 functions to snapshot file (~196KB)
  3. Sources snapshot in non-interactive shell (where .zshrc is NOT loaded)
  4. Function definitions reference commands that don't exist

Example from actual snapshot:

$ grep -A 3 "^cd ()" ~/.claude/shell-snapshots/snapshot-zsh-*.sh
cd () {
	__zoxide_z "$@"
}

$ grep "__zoxide_z ()" ~/.claude/shell-snapshots/snapshot-zsh-*.sh
# (no output - dependency not captured)

The broken contract:

  • Interactive context: .zshrc loads → zoxide init → defines __zoxide_z → defines cd wrapper
  • Non-interactive context: .zshrc NOT loaded → __zoxide_z missing → cd function fails

Environment

  • Claude Code Version: 2.0.19
  • Shell: zsh (issue likely affects zsh users specifically)
  • OS: macOS Darwin 24.6.0 (likely affects Linux as well)
  • Reproduction Rate: 100% with zoxide or similar tools

Additional Context

Related to GitHub Issue #3601: Shell snapshot migration from file-based to in-memory implementation. This architectural issue persists in the new implementation.

Impact scope:

  • cd with zoxide's --cmd cd flag ❌
  • ls if aliased to eza/exa
  • cat if aliased to bat
  • Any fzf keybinding functions ❌
  • Custom functions using plugin commands ❌
  • Framework-specific commands (zinit, oh-my-zsh) ❌

Current workarounds:

  1. Guard interactive customizations in .zshrc:

``bash
if [[ -o interactive ]]; then
eval "$(zoxide init zsh --cmd cd)"
fi
``

  1. Use alternative command names (don't override builtins):

``bash
eval "$(zoxide init zsh)" # Creates 'z' command instead of overriding 'cd'
``

Suggested Fixes

  1. Dependency resolution during capture: Recursively capture function dependencies or skip functions with missing dependencies
  1. Match execution context: If snapshot is from interactive shell, execute commands with zsh -i -c to load .zshrc
  1. Selective capture: Only capture shell state valid in non-interactive contexts (skip builtin overrides)
  1. Clear error handling: Detect missing dependencies and fail with actionable guidance

Files Available

Can provide:

  • Shell snapshot files
  • .zshrc configuration
  • Complete reproduction environment
  • Any other debugging information needed

View original on GitHub ↗

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