[BUG] Environment variables expand to empty strings when used in piped commands
Resolved 💬 2 comments Opened Jan 9, 2026 by xwang233 Closed Jan 9, 2026
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?
Environment variables expand to empty strings when commands contain pipes in the Bash tool.
What Should Happen?
Environment variables should be correctly expanded in piped commands, just as they are in non-piped commands.
Error Messages/Logs
# Debug output shows variable already empty before execution:
set -x; echo "Value: ${SECRET_TOKEN}" | cat; set +x
+(eval):1> echo 'Value: ' # Variable expanded to empty
+(eval):1> cat
Steps to Reproduce
- Set an environment variable: export SECRET_TOKEN="abc123"
- Test without pipe: echo "Token: ${SECRET_TOKEN}" → Works: "Token: abc123"
- Test with pipe: echo "Token: ${SECRET_TOKEN}" | cat → Fails: "Token: "
Claude Model
None
Is this a regression?
Yes, this worked in a previous version
Last Working Version
_No response_
Claude Code Version
2.1.2 (Claude Code)
Platform
Anthropic API
Operating System
Other Linux
Terminal/Shell
VS Code integrated terminal
Additional Information
- This is a bug in Claude Code's Bash tool, not the user's shell environment
- Bug confirmed in both bash and zsh environments
- When instructing Claude Code to use the Bash tool:
- echo "${SECRET_TOKEN}" → Works
- echo "${SECRET_TOKEN}" | cat → Fails (empty string)
- bash -c 'echo "${SECRET_TOKEN}" | cat' → Works
- Root cause: Bash tool executes via bash/zsh -c -l source snapshot.sh && eval 'command', variable expansion happens at wrong parsing stage when pipes are present
! echo $TEST_SECRET
⎿ mysecret123
❯ Can you run these commands using your Bash tool and tell me the results?
1. Without pipe:
echo "Value: ${TEST_SECRET}"
2. With pipe:
echo "Value: ${TEST_SECRET}" | cat
3. With bash -c wrapper:
bash -c 'echo "Value: ${TEST_SECRET}" | cat'
Also, can you show me what shell process is being used?
ps -p $$ -o cmd=
● I'll run these commands for you using the Bash tool to show the different behaviors.
● Bash(echo "Value: ${TEST_SECRET}")
⎿ Value: mysecret123
● Bash(echo "Value: ${TEST_SECRET}" | cat)
⎿ Value:
● Bash(bash -c 'echo "Value: ${TEST_SECRET}" | cat')
⎿ Value: mysecret123
● Bash(ps -p $$ -o cmd=)
⎿ /bin/bash -c -l source /root/.claude/shell-snapshots/snapshot-bash-1767989188783-j4g8gy.sh && shopt -u extglob 2>/dev/null || true && eval 'ps -p $$ -o cmd=' \< /dev/null && pwd -P >| /tmp/claude-c590
-cwd
● Here are the results:
1. Without pipe:
Value: mysecret123
✓ The environment variable is expanded correctly.
2. With pipe:
Value:
✗ The environment variable is NOT expanded when piped through cat.
3. With bash -c wrapper:
Value: mysecret123
✓ Using bash -c preserves the environment variable expansion even with the pipe.
Shell process:
/bin/bash -c -l source /root/.claude/shell-snapshots/snapshot-bash-1767989188783-j4g8gy.sh && shopt -u extglob 2>/dev/null || true && eval 'ps -p $$ -o cmd=' < /dev/null && pwd -P >| /tmp/claude-c590-cwd
The shell is /bin/bash. The interesting behavior you're seeing is that when using pipes directly, the environment variable expansion appears to fail, but wrapping the entire command in bash -c preserves it. This is likely due to how the command execution environment handles variable expansion in different contexts.This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗