[Bug] Bash tool silently strips backslashes on Windows/Git Bash

Status Open
Maintainer reply None cached
Activity 1 comment · opened Aug 25, 2026

Bug Description
Bash tool silently collapses \\ to \ in commands on Windows/Git Bash ## Summary On Windows, the Bash tool destroys one backslash from every \\ pair in the command string, somewhere between the stored tool input and the bash argv. Bash never receives the second backslash, so no amount of correct quoting in the command can protect the content — including a quoted heredoc (<<'EOF'), which by POSIX must do zero processing. This is silent. Writing C# via a heredoc turns "tools\\bench.cmd" into "tools\bench.cmd". \b is a valid C# escape (backspace), so it compiles clean and tests pass; the defect surfaces later at runtime. JSON would fail loudly, C#/regex will not. ## Environment - Claude Code 2.1.243 (latest at time of report) - Windows 11 Pro 10.0.26200 - GNU bash 5.3.15(1) (x86_64-pc-cygwin), MINGW64_NT-10.0-26200 - git 2.55.0.windows.3, shell /bin/bash.exe - permissions.defaultMode: "auto" ## Reproduction Single Bash tool call: printf '%s' 'M\\N' > /tmp/bs.txt; od -c /tmp/bs.txt Expected: M \ \ N Actual: M \ N Same result with a quoted heredoc, which should be fully literal: cat > /tmp/hd.txt <<'EOF' var p = "tools\\bench.cmd"; EOF od -c /tmp/hd.txt # -> tools\bench.cmd ## Evidence: chain of custody for one backslash Three measurement points on the same printf '%s' 'M\\N' call: | stage | backslashes | measured by | |----------------------------------------|-------------|------------------------| | model -> harness, Bash tool input | 2 M\\N | session JSONL via jq | | model -> harness, Write tool (control) | 2 | session JSONL via jq | | harness -> bash argv | 1 M\N | /proc/$$/cmdline | | resulting file | 1 M\N | od -c | The session transcript holds two backslashes, so the model emitted them and the harness received them. /proc/$$/cmdline — the literal argv bash was launched with — holds one. Bash cannot have eaten a byte it never got. To reproduce the argv half, add to the same call: cat /proc/$$/cmdline | tr '\0' '\n' and to reproduce the transcript half: jq -r '.message.content[]? | select(.type=="tool_use") | select(.input.command? // "" | contains("bs.txt")) | .input.command' \ ~/.claude/projects/<project>/<session-id>.jsonl | od -c ## Signature - \\ -> \ (collapsed) - \", \t, \d, \s, lone \ -> unchanged - \\\\ -> \\ (so exactly one level is stripped) Independent of quoting: reproduces inside single quotes, inside <<'EOF', and with no quotes at all. That pattern looks like un-doubling of escaped Windows path separators being applied to the entire command string rather than only to paths. The bash invocation on Windows is wrapped in a Windows-specific preamble (export TEMP='C:\Users\...' ... && eval '<command>') that handles paths with single backslashes, which seems the likely home for it — though I've localized this by measurement, not by reading the code. ## Ruled out - Bash quoting: reproduces where POSIX guarantees literal handling. - The eval wrapper: the doubled backslash is already gone in argv, before eval runs. - Model-side escaping: the Write tool control in the same session carried \\ through intact, and the transcript shows the Bash input arrived with both backslashes. ## Impact Wider than file writing — any Bash command carrying \\ is affected, including sed scripts and grep patterns. While investigating, my own diagnostic grep -oE 'M\\+N' arrived as M\+N and silently matched nothing. Severity is amplified by defaultMode: "auto", whose standing instruction is to "make file changes with sed, heredocs, or short scripts, rather than using the dedicated Read, Edit, or Write tools." That routes file authoring through the defective path by default. On a C#/JSON codebase this corrupts source silently and at scale. Agents cannot work around it: their quoting is already correct, and the bytes are destroyed after the model is done. The only mitigation is avoiding Bash for backslash-bearing content, which is in direct tension with auto mode.

Environment Info

  • Platform: win32
  • Terminal: windows-terminal
  • Version: 2.1.243
  • Feedback ID: 3eaf988c-6f7d-401b-b35c-32351f301e03

Errors

[]

View original on GitHub ↗

This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗