[BUG] Read tool fails with "Invalid regular expression: missing terminating ]" for every cwd-internal path, session-wide

Resolved 💬 3 comments Opened May 3, 2026 by jdwyah Closed Jun 2, 2026

Bug

In a Claude Code session, every Read tool call against a path under cwd fails with:

Invalid regular expression: missing terminating ] for character class

The error is reliable for the entire session and fires on the very first Read call. It is also reproducible across multiple fresh sessions in the same cwd, so the trigger is stable state in the project, not session corruption.

Scope is path-based, not file-based

  • Read("/Users/<user>/code/<project>/anything.md") (inside cwd) → regex error
  • Read("/Users/<user>/.claude/settings.json") (outside cwd) → succeeds
  • Read("/tmp/does-not-exist.txt") (outside cwd) → File does not exist (correct error, not regex error)

The regex error fires before any file I/O — same failure with limit=5 on a real file.

Edit and Write are also affected

  • Edit(...) against any cwd-internal file → File has not been read yet (Edit gates on Read having succeeded)
  • Write(...) to a brand-new cwd-internal path that was never Read → same regex error
  • Write(...) to a path outside cwd → succeeds

So the gate is path-based, not Read-state pollution.

Workarounds (Bash tool unaffected)

  • File reads: awk 'NR>=X && NR<=Y' <file>
  • File creation: cat > <path> <<'EOF' ... EOF
  • Edits: python3 inline script with exact-string .replace()

Each unique line range needs its own permission approval unless Bash(awk:*) is allowlisted, so the bug is very disruptive in practice.

What I ruled out by exhaustive scanning

I scanned every file under cwd that Claude Code might plausibly load, looking for an unmatched [ (whole-file count, per-line, and frontmatter-only):

  • CLAUDE.md and ~20 sub-repo CLAUDE.md files
  • AGENTS.md and sub-repo AGENTS.md files
  • .claude/rules/*.md
  • .claude/skills/*/SKILL.md (frontmatter AND bodies)
  • .claude/agents/*.md
  • .claude/settings.local.json and sub-repo .claude/settings.json
  • ~/.claude/settings.json, ~/.claude/settings.local.json, ~/.claude.json
  • All 57 .gitignore / .ignore / .rgignore / .dockerignore / .npmignore / .eslintignore / .prettierignore files
  • ~/.gitignore (global excludesfile)
  • All memory files in ~/.claude/projects/<project>/memory/
  • tsconfig*.json, .editorconfig, .prettierrc*, .eslintrc*, .gitattributes

No unmatched [ found in any of these. So the failing regex is most likely constructed programmatically (e.g., glob-to-regex conversion of a permission pattern), not read directly from text.

Suspected source: permission patterns in project settings.local.json

The affected project's .claude/settings.local.json has unusual entries that a naive glob-to-regex converter could mishandle:

"Read(//Users/<user>/code/<project>/launch-migrator/.../schemas/**)"
"Read(//Users/<user>/code/<project>/$dir/**)"
"Bash(find /Users/<user>/code/<project>/app-foo/src -type f \\\\\\(-name *detail* -o -name *evaluation* -o -name *chart* -o -name *tab* \\\\\\))"

Notable: leading //, literal $dir in a glob, and triple-backslash-escaped parens (\\\(...\\\) after JSON decode).

I cannot bisect from inside the affected session because the gate fires before tool input is processed. The cleanest next step is for someone with source access to add logging at every new RegExp(...) reachable from the Read tool's path/permission pre-validation, then drive a Read against any path under the cwd to capture the offending pattern.

Related

Same class of bug as #39654 (Skill tool's arguments frontmatter compiled as regex without escaping; [--mode MODE] triggers Invalid regular expression: unmatched parentheses). Different code path — likely Read's path/permission pre-validation here rather than getPromptForCommand.

Same fix template applies:

const escaped = pattern.replace(/[\.*+?^${}()|\[\]\\]/g, '\\$&');
new RegExp(escaped);

Environment

  • Claude Code: 2.1.126
  • Binary: /Users/<user>/.local/share/claude/versions/2.1.126 (Mach-O 64-bit arm64, bun-bundled JS)
  • macOS: Darwin 25.2.0 (arm64)
  • Shell: fish (irrelevant — Bash tool fallback works)
  • Model: claude-opus-4-7[1m] (Opus 4.7, 1M context)

View original on GitHub ↗

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