claude-code - 💡(How to fix) Fix [BUG] Bash tool incorrectly escapes ! characters — still reproducible as of May 2026

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…

Error Message

jq: error: syntax error, unexpected INVALID_CHARACTER at <top-level>, line 1: select(.status != "inactive")

Root Cause

Root Cause

Fix Action

Fix / Workaround

Workaround

Code Example

jq: error: syntax error, unexpected INVALID_CHARACTER at <top-level>, line 1:
select(.status \!= "inactive")

---

jq: error: syntax error, unexpected INVALID_CHARACTER at <top-level>, line 1:
select(.status \!= "inactive")
                ^
jq: 1 compile error

---

echo '{"status":"active"}' | jq 'select(.status != "inactive")'

---

{
  "status": "active"
}

---

jq: error: syntax error, unexpected INVALID_CHARACTER at <top-level>, line 1:
select(.status \!= "inactive")

---

- s.replace(/(["\\$!])/g, "\\$1")
+ s.replace(/(["\\$])/g, "\\$1")
RAW_BUFFERClick to expand / collapse

Preflight Checklist

What's Wrong?

The Bash tool auto-escapes ! to \! before commands reach the shell. This was previously tracked in #17495 (the only non-duplicate report, now closed) but the bug is still present.

The escaping happens at the transport layer regardless of quoting style, which means it affects not just shell interpretation but any argument passed to a subprocess — SQL, jq filters, awk expressions, language runtimes, etc.

Actual output when running a jq filter with !=:

jq: error: syntax error, unexpected INVALID_CHARACTER at <top-level>, line 1:
select(.status \!= "inactive")

Impact:

  • jq: != and !~ operators become \!= / \!~ → syntax error
  • awk: negation operator ! becomes \! → backslash not last character on line
  • SQL via CLI: WHERE status != 'x' becomes WHERE status \!= 'x' → database syntax error
  • Ruby bang methods: save!, create!, find_or_create_by! break when run inline (originally reported in #17495)

The model generates != and ! correctly — the corruption is introduced entirely by the tool's command-quoting pipeline.

What Should Happen?

The jq filter select(.status != "inactive") should execute correctly and return {"status":"active"} without any modification to the != operator.

Error Messages/Logs

jq: error: syntax error, unexpected INVALID_CHARACTER at <top-level>, line 1:
select(.status \!= "inactive")
                ^
jq: 1 compile error

Steps to Reproduce

Ask Claude Code to run this shell command via the Bash tool:

echo '{"status":"active"}' | jq 'select(.status != "inactive")'

Expected output:

{
  "status": "active"
}

Actual output:

jq: error: syntax error, unexpected INVALID_CHARACTER at <top-level>, line 1:
select(.status \!= "inactive")

The ! in != is escaped to \! by the tool's quoting pipeline before the command reaches the shell. Since bash -c runs a non-interactive shell (history expansion disabled), the backslash is not consumed and passes verbatim to jq as \!=, causing a syntax error.

Claude Model

None

Is this a regression?

Yes, this worked in a previous version

Last Working Version

No response

Claude Code Version

latest (as of May 2026)

Platform

Anthropic API

Operating System

macOS

Terminal/Shell

Terminal.app (macOS)

Additional Information

Root Cause

The bundled shell-quote library escapes ! via the regex /(["\\$\!])/g. This is meant to prevent Bash history expansion, but Claude Code invokes commands with bash -c (non-interactive), where history expansion is disabled by default. The backslash is never consumed by Bash and passes verbatim to subprocesses.

Proposed Fix

Remove ! from the escape regex:

- s.replace(/(["\\$!])/g, "\\$1")
+ s.replace(/(["\\$])/g, "\\$1")

If suppressing history expansion is desired, it should be handled at the shell level (set +H) rather than in the transport layer.

Workaround

Use ANSI-C hex escaping: $'\x21' instead of !. This bypasses the transport layer's pre-processing.

Related issues (all closed as duplicates, bug still present)

Supersedes / closes: #17495 Duplicates: #2941, #7387, #23740, #24979, #29210, #32864

This report is a re-open of #23740, which was auto-closed as a duplicate of #10335, but the underlying bug has not been fixed.

(I let Claude generate this issue. Sorry if it's really bad, but what are you doing that you simply auto-close issues that have been reported many times without having a way to re-open them easily...)

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

claude-code - 💡(How to fix) Fix [BUG] Bash tool incorrectly escapes ! characters — still reproducible as of May 2026