[BUG] Bash tool: 'undefined is not an object (evaluating H.replace)' on heredoc-write + compound commands (v2.1.144)

Resolved 💬 3 comments Opened May 19, 2026 by iamdevnull Closed May 23, 2026

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-vfs on /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):

  1. Heredoc + redirect (highest-firing): cat > /path/file << 'EOF' ... EOF and variants
  2. for-do-done loop as one Bash invocation: for x in a b c; do cmd1; cmd2; done
  3. ≥3 statement-chains via ; outside quoted regions
  4. 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

View original on GitHub ↗

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