[BUG] Bad substitution when using heredocs with ${var} — runner not using bash

Resolved 💬 3 comments Opened Jan 15, 2026 by PabloZavi Closed Jan 18, 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?

Claude Code throws a Bad substitution error when executing commands that include heredocs whose content contains ${var} (e.g. ${i}).

This happens even though the UI indicates the command is executed as Bash(...).

The error originates from the command runner, not from the project code, and often results in:

  • Bad substitution shell errors
  • Unhandled promise rejections
  • Subsequent API Error: 400 due to tool use concurrency issues

Followed in many cases by an unhandled promise rejection and an API 400 error due to tool concurrency issues.

What Should Happen?

The heredoc content should be written verbatim to the file without any shell interpolation or preprocessing by the runner.

Error Messages/Logs

This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). The promise rejected with the reason: Error: Failed to parse command: Bad substitution: i at ubH (/$bunfs/root/claude:4317:122) at yW (/$bunfs/root/claude:4320:195) at rZ$ (/$bunfs/root/claude:4320:1714) at isReadOnly (/$bunfs/root/claude:2894:1961) ● Bash(cd "/home/pabloz/near-intents-amm-solver/scripts/[v5]transaction-observer" && cat > list-failed-tokens.ts << 'EOF' timeout: 10s atimporty*oas>fs/fromf'fs';…)claude:3072:11288) ⎿  Waiting… at KA1 (/$bunfs/root/claude:3072:11153) at v_A (/$bunfs/root/claude:3072:10730)

Steps to Reproduce

  1. Ask Claude Code to create a file using a heredoc.
  2. Include ${i} or ${var} inside the heredoc content.
  3. Let Claude execute the generated command.

Example command:

cat > test.ts << 'EOF'
for (const i of items) {
  console.log(`Item ${i}`);
}
EOF

### Claude Model

Sonnet (default)

### Is this a regression?

I don't know

### Last Working Version

_No response_

### Claude Code Version

2.1.7 (Claude Code)

### Platform

Anthropic API

### Operating System

Ubuntu/Debian Linux

### Terminal/Shell

WSL (Windows Subsystem for Linux)

### Additional Information

_No response_

View original on GitHub ↗

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