[BUG] Bash tool escapes ! to \! inside JSON strings in single-quoted arguments (regression 2.1.87)

Resolved 💬 3 comments Opened Mar 30, 2026 by NasAndNora Closed Apr 3, 2026

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet
  • [x] This is a single bug report
  • [x] I am using the latest version of Claude Code

What's Wrong?

The Bash tool escapes ! to \! when it appears inside double-quoted strings ("...") within single-quoted arguments ('...'). Single quotes should protect all characters — no escaping should occur.

This breaks any CLI command that passes JSON with ! as an inline argument.

What Should Happen?

! inside single-quoted arguments should be passed as-is to the subprocess, with no escaping.

Error Messages/Logs

# ! inside "..." gets escaped
$ python3 -c "import sys; print(repr(sys.argv[1]))" '{"range":"Feuille 1!A11"}'
'{"range":"Feuille 1\\!A11"}'

# ! outside "..." is fine
$ python3 -c "import sys; print(repr(sys.argv[1]))" 'hello!world'
'hello!world'

Steps to Reproduce

  1. Open Claude Code 2.1.87
  2. Ask Claude to run:

``
python3 -c "import sys; print(repr(sys.argv[1]))" '{"key":"val!ue"}'
``

  1. Output shows \\! instead of !
  2. Any CLI tool parsing that JSON (e.g. serde_json, json.loads) fails with "invalid escape"

Real-world impact: Google Workspace CLI (gws) uses --params '<JSON>' for API calls. Google Sheets A1 notation requires ! to specify a sheet name (e.g. Sheet1!A1:B2). Every Sheets API call targeting a named tab fails:

gws sheets spreadsheets values get --params '{"spreadsheetId":"...","range":"Feuille 1!A11"}'
# → "Invalid --params JSON: invalid escape at line 1 column 84"

Workaround: Write JSON to a temp file and use "$(cat /tmp/file.json)" — heredocs with quoted delimiters bypass the escaping.

Is this a regression?

Yes, this worked in a previous version.

Last Working Version: 2.1.86

Environment

  • Claude Code Version: 2.1.87
  • Platform: Anthropic API
  • OS: macOS (Darwin 25.3.0, aarch64)
  • Terminal: Terminal.app
  • Shell: zsh
  • Install: Standalone installer (~/.local/share/claude/versions/)
  • Model: Opus

View original on GitHub ↗

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