[BUG] Bash tool: 'undefined is not an object (evaluating H.replace)' on heredoc-write + compound commands (v2.1.144)
Environment
- Claude Code version: 2.1.144
- OS: Linux 6.19.14+kali-amd64 x86-64
- Runtime: Bun (single-binary ELF, JavaScriptCore — confirmed via
file+strings | grep bun-vfson/home/masi/.local/share/claude/versions/2.1.144)
Symptom
Bash tool returns:
Error: undefined is not an object (evaluating 'H.replace')
— with no stdout / stderr. The command never reaches the shell. The error originates in the TUI display-layer renderer pipeline, before tool execution.
Empirical trigger
30+ occurrences observed in a single 4-hour wifi-hub session (transcript b4f8d568-13a8-4e55-a83f-9cde71f4908b) plus 5+ in subsequent sessions. Empirical common-denominator of triggering commands (any one is sufficient):
- Heredoc + redirect (highest-firing):
cat > /path/file << 'EOF' ... EOFand variants - for-do-done loop as one Bash invocation:
for x in a b c; do cmd1; cmd2; done - ≥3 statement-chains via
;outside quoted regions - Mixed
&&+;in the same command
Reliable minimal repro:
cat > /tmp/test.py << 'EOFPY'
#!/usr/bin/env python3
print("hi")
EOFPY
Single-statement, non-heredoc commands (git status, ls -la, echo hi) never fire the error.
Root cause analysis (RE-grounded)
Strings-dump of the Bun-bundled CLI binary surfaced 12 distinct unguarded H.replace call sites in the renderer pipeline. Examples:
function px(H){return H.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")} // regex-escape
function H$q(H){return H.replace(/[^A-Za-z0-9\-._~!$&'()*+,;=:@]+/g,encodeURIComponent)} // URL-encode
function $E$(H){return H.replace(/[0-9]/g,...)} // Unicode fullwidth-digit normalise
function S8q(H){if(h8q)return h8q(H);return H.replace(zz9,"�")}
function GR8(H){if(typeof H=="number")return\`\${H}\`;return H.replace(/~/g,"~0").replace(/\//g,"~1")}
None of the 12 sites guard H with optional chaining or a typeof check. When the command-summary extraction returns undefined for heredoc/compound shapes, the downstream normaliser calls .replace() on undefined and crashes.
Same architectural shape as related issues
- #43663 (closed-stale, 2026-04-04) — \
H.command\undefined in \isSearchOrReadCommand\. Verbatim root-cause from reporter: "isSearchOrReadCommand(q) guards with \if (!q.command)\but crashes when q itself is undefined. The null check should be \if (!q?.command)\." - #60511 (open, v2.1.144) — re-open of #43663, same \
H.command\shape on Windows/Bun. - #54505 (open, v2.1.122) — \
H.map\variant on AskUserQuestion subsequent calls.
All four issues (including this one) share: TUI display-layer classifier/renderer expects non-null first-arg field, crashes when field missing — missing optional-chain at function entry.
Suggested upstream fix
Add an optional-chain or typeof guard to every \H.replace\ site in the renderer pipeline:
// before
function px(H){return H.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}
// after — option A: optional-chain + nullish-coalesce
function px(H){return H?.replace(/[.*+?^${}()|[\]\\]/g,"\\$&") ?? ""}
// after — option B: typeof guard
function px(H){if(typeof H!=="string")return H;return H.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}
Better: fix the upstream command-summary extractor that produces \undefined\ for heredoc/compound shapes — but that requires source-level investigation. The defensive guards at every \.replace()\ site are a strict subset of the proper fix and would block the crash even if the upstream extractor stays buggy.
Impact
- Disrupts every session that uses heredoc-write or compound shell commands (very common in setup / probe / iteration workflows)
- Forces the agent to split commands into separate Bash invocations as a workaround, costing ~1k tokens per extra call
- Confirmed cross-platform (Linux/Bun here, Windows/Bun in #60511) — not OS-specific
Workaround (client-side)
Split compound commands into separate Bash invocations; stage heredoc payloads as files via the Write tool then run them. We document this in our local kb at kb/known-issues-claude-code.md and have built a PreToolUse:Bash advisory hook (bash-h-replace-preventer.py) that warns when a command's shape matches the empirical trigger set before submission.
🤖 Reported with Claude Code
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗