[Bug] Bash tool: zsh command resolution fails after compound pipelines with while-read and &&-chains

Resolved 💬 3 comments Opened May 16, 2026 by JoeWolf1 Closed May 20, 2026

Bug Description
Title: Bash tool: zsh "command not found" for external commands after compound pipelines, even with
full PATH

Summary
After certain compound Bash commands (multi-stage pipe ending in while read,
followed by &&-chained external commands), the post-&& commands fail with
(eval):1: command not found: <cmd> even though $PATH is fully populated and
the commands resolve fine in direct probes. Substituting absolute paths
(/bin/ls vs ls) makes the same command work — so PATH-the-variable is
correct, but the shell's command-lookup machinery is broken in the post-pipeline
eval context.

Environment

  • macOS, zsh 5.9
  • Claude Code CLI (current build)
  • Shell: /bin/zsh (interactive zsh; verified $SHELL, $0, $ZSH_VERSION)

Minimal repro (fails)
cd ~/.claude && true ; printf 'X~/.claude/doctrine/a.mdX\n' | sort -u | \
sed 's/X//g; s|~/|/Users/joewolf/|' | \
while read path; do
if [ -e "$path" ]; then echo "OK"; else echo "MISSING"; fi
done && ls doctrine/ | wc -l

Output:
MISSING
(eval):1: command not found: ls
(eval):1: command not found: wc

Same command with /bin/ls and /usr/bin/wc substituted — WORKS:
... done && /bin/ls doctrine/ | /usr/bin/wc -l

Output:
MISSING

Diagnostic findings

  1. $PATH is fully populated in every direct probe (top-level, inside

while-read body, after &&-chain, inside command substitution). Full PATH
includes /usr/bin and /bin where ls/wc/basename live.

  1. which ls, which basename, which wc all resolve to /bin/ls,

/usr/bin/basename, /usr/bin/wc in direct probes.

  1. The error prefix (eval):1: is zsh's specific format for commands run

through eval — the post-pipeline &&-chained commands ARE being eval'd
somewhere in the tool chain, not run directly.

  1. Absolute paths bypass the broken lookup and work normally → confirms

PATH-the-variable is fine, but PATH-based command resolution is broken in
that eval context.

  1. Likely cause: zsh command hash-table is in a degraded/cleared state in the

re-eval context, but $PATH itself is preserved. zsh normally hashes
PATH-directory contents on first lookup; if hash is invalidated without
rehash, subsequent PATH-relative commands fail until rehash.

Why non-deterministic-looking on first bisection
Structural triggers don't bisect cleanly — minor differences in command
structure (one sed substitution vs two, presence of ~/ in input, etc.)
flip between working and failing in confusing ways. This suggests the
trigger isn't purely structural in zsh — it's likely in how Claude Code's
Bash tool processes the command string before passing it to zsh (token
length threshold, sandbox heuristic, hash-eviction timing, or hook
intercepting+re-eval'ing parts of compound commands).

Smoking-gun probe pair (deterministic)
Same command, two outcomes — only difference is bare command names vs absolute paths:

# FAILS:
... | while read path; do ...; done && ls doctrine/ | wc -l

# WORKS:
... | while read path; do ...; done && /bin/ls doctrine/ | /usr/bin/wc -l

Workarounds (in order of preference)

  1. Absolute paths for external commands after long pipelines
  2. Split compound commands into separate Bash tool calls
  3. Avoid while read followed by &&-chains with external commands in

a single Bash invocation

Severity
Low (workaround is trivial), but high "wasted-debugging-time" potential —
the failure mode looks like a PATH bug but isn't, and the non-deterministic-
looking bisection chews through context budget before the smoking-gun absolute-
path test reveals the real cause.

Repro file count: tested against 14 probes; both reproducible failures and
working variants captured. Happy to share the full probe transcript if useful.

Environment Info

  • Platform: darwin
  • Terminal: Apple_Terminal
  • Version: 2.1.143
  • Feedback ID: 521ccab5-059c-4f7f-b447-b58d2c111a34

Errors

[{"error":"Error: Stream idle timeout - partial response received\n    at DSK (/$bunfs/root/src/entrypoints/cli.js:9089:15603)\n    at processTicksAndRejections (native:7:39)","timestamp":"2026-05-16T14:32:45.578Z"},{"error":"Error: The socket connection was closed unexpectedly. For more information, pass `verbose: true` in the second argument to fetch()\n    at from (/$bunfs/root/src/entrypoints/cli.js:118:7862)\n    at <anonymous> (/$bunfs/root/src/entrypoints/cli.js:126:12898)\n    a…

Note: Content was truncated.

View original on GitHub ↗

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