[BUG] Edit tool fails silently when file contains non-breaking spaces (U+00A0)
Description
The Edit tool fails to match old_string when the target file contains non-breaking spaces (U+00A0, UTF-8 bytes c2 a0). The model generates regular spaces (0x20) in the old_string parameter, but the file contains visually identical non-breaking spaces, causing a silent "String to replace not found" error.
Steps to Reproduce
- Have a markdown file containing non-breaking spaces (common when content was copy-pasted from rich text sources like Notion, Google Docs, or AI-generated output)
- Read the file with the Read tool — non-breaking spaces render identically to regular spaces
- Attempt to edit a line containing a non-breaking space using the Edit tool
- Edit fails with "String to replace not found in file"
Example
File content (hex dump of affected line):
68 65 20 74 61 73 6b 20 6c 69 73 74 20 69 6e c2 a0 63 75 72 72 65 6e 74
^^^^^
U+00A0 non-breaking space
The Read tool displays this as: the task list in current
The model generates old_string with: the task list in current (using 0x20)
The Edit tool fails because 0x20 ≠ c2 a0
Root Cause
The model has no way to distinguish non-breaking spaces from regular spaces in the Read tool output — they are visually identical. When it constructs the old_string for the Edit tool, it naturally uses regular ASCII spaces. The Edit tool performs strict byte-for-byte matching, so the mismatch causes a silent failure.
Impact
- Hard to diagnose: The error message gives no hint about the whitespace mismatch. Users see "String to replace not found" for text that appears to match exactly.
- Common source: Non-breaking spaces are silently introduced by copy-paste from rich text editors (Notion, Confluence, Google Docs), macOS
Option+Spacekeystrokes, and some AI-generated content. - Workaround tax: The only workaround is to use
hexdumpto identify the issue, then fall back to Python/sed for the replacement — defeating the purpose of the Edit tool.
Suggested Fix
The Edit tool could normalize Unicode whitespace characters (U+00A0, U+2007, U+202F, etc.) to ASCII space (0x20) during string matching, while preserving the replacement behavior. Alternatively, the Read tool could annotate or flag non-ASCII whitespace characters.
Related Issues
This is the same class of problem as:
- #15920 — Edit tool corrupts/can't match Unicode typographic characters (e.g.,
'U+2019) - #9163 / #13152 — Edit tool can't match tab characters (Read displays as spaces, Edit expects literal tabs)
- #18050 — Edit tool cannot match literal tab characters in old_string/new_string
- #29699 — Edit tool Unicode-to-ASCII mojibake on Windows
All share the same root cause: the Read tool and Edit tool have inconsistent representations of special characters, and the model cannot bridge the gap.
Environment
- Claude Code (CLI)
- macOS Darwin 25.3.0
- Files: Markdown (
.md) instruction files in.claude/directory
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗