[Bug] Edit tool fails on mixed literal/escape Unicode in multi-line old_string

Open 💬 4 comments Opened Jun 1, 2026 by wodin

Bug Description
The bug from #52813 is still reproducible on the current version of Claude Code. The Edit tool fails when a multi-line old_string spans a region where the same Unicode character appears as both a literal codepoint and a \uXXXX source escape. The whole-string swap fallback tries "all literals" and "all escapes" but can't handle the mixed case. The workaround remains: use sed/node/bun via Bash for these edits.

Environment Info

  • Platform: linux
  • Terminal: vte-based
  • Version: 2.1.159
  • Feedback ID: d91c74c4-b5a6-4613-aac3-e059e0305fc5

Errors

 ▐▛███▜▌   Claude Code v2.1.159
▝▜█████▛▘  Opus 4.6 · Claude Max
  ▘▘ ▝▝    ~/.claude


❯ Can you still reproduce the following issue?                                  
  https://github.com/anthropics/claude-code/issues/52813                        

● Let me fetch that issue to understand what it reports.

● Bash(gh issue view 52813 --repo anthropics/claude-code --json
      title,body,state,labels,comments 2>&1 | head -200)
  ⎿  {"body":"## Summary\n\nThe `Edit` tool appears to transparently conver
     t between `\\uXXXX` escape sequences and their literal Unicode codepoi
     nts when matching `old_string` against file contents. When the target
     … +229 lines (ctrl+o to expand)

● Got it. The issue is about the Edit tool silently normalizing \uXXXX escape
  sequences before matching, making it impossible to edit files that contain
  literal backslash-u escape sequences. Let me reproduce it.

● Bash(mkdir -p /tmp/claude-edit-repro && cat > /tmp/claude-edit-repro/repro.ts
      << 'ENDOFFILE'
      const key = s.replace(/ /g, ' ');…)
  ⎿  0000000   c   o   n   s   t       k   e   y       =       s   .   r
     e
     0000020   p   l   a   c   e   (   / 302 240   /   g   ,       '
     … +3 lines (ctrl+o to expand)

● Interesting — the file already doesn't contain the literal \u00A0 ASCII
  characters. The tool input may have been normalized before reaching bash. Let
  me try creating the file with explicit hex bytes.

● Bash(printf 'const key = s.replace(/\\u00A0/g, '"'"' '"'"');\n' >
      /tmp/claude-edit-repro/repro.ts && od -c /tmp/claude-edit-repro/repro.ts)
  ⎿  0000000   c   o   n   s   t       k   e   y       =       s   .   r
     e
     0000020   p   l   a   c   e   (   /   \   u   0   0   A   0   /   g
     … +3 lines (ctrl+o to expand)

● Good — the file now contains the literal six ASCII characters \, u, 0, 0, A,
  0. Let me verify with Read and then attempt the Edit.

  Read 1 file (ctrl+o to expand)

● Now let me attempt to use Edit to replace this line. I'll try to match the
  line containing \u00A0.

● Update(/tmp/claude-edit-repro/repro.ts)
  ⎿  Added 1 line, removed 1 line
      1 -const key = s.replace(/\u00A0/g, ' ');                          
      1 +const key = s.replace(/\u00A0/g, ' ').trim();                   

● The edit appeared to succeed. Let me check what the file actually contains
  now.

● Bash(od -c /tmp/claude-edit-repro/repro.ts)
  ⎿  0000000   c   o   n   s   t       k   e   y       =       s   .   r
     e
     0000020   p   l   a   c   e   (   /   \   u   0   0   A   0   /   g
     … +3 lines (ctrl+o to expand)

● The simple case worked — the Edit tool's fallback normalization handled it.
  But the issue describes a harder case: when the same character appears as both
  a literal codepoint AND a \uXXXX escape in the same file region. Let me try
  that.

● Bash(printf '// Sample dessert price ranges.\nconst ranges = [\n  "Cookie
      price: $2 \xe2\x80\x94 $5",\n  "Cake price:   $20 \\u2014
      $40",\n]\n\nexport default ranges…)
  ⎿  0000000   /   /       S   a   m   p   l   e       d   e   s   s   e
     r
     0000020   t       p   r   i   c   e       r   a   n   g   e   s   .  \
     … +15 lines (ctrl+o to expand)

● The file has the mixed form: line 3 has the literal em-dash codepoint (3 UTF-8
  bytes 342 200 224), and line 4 has the 6 ASCII characters \u2014. Now let me
  read it and attempt the Edit.

  Read 1 file (ctrl+o to expand)

● Now the critical test — trying to edit both price lines at once, which spans
  the mixed representation:

● Update(/tmp/claude-edit-repro/recipes.ts)
  ⎿  Error editing file

● Yes, the bug is still reproducible. The exact error from the issue appears,
  word for word.

  ★ Insight ─────────────────────────────────────

  Why this happens: The fundamental issue is a representation gap between JSON
  and file bytes.

  1. JSON conflation: In JSON, \u2014 and the literal — character are the same
  value. By the time the Edit tool receives old_string, it has one em-dash
  codepoint — there's no way for the caller to distinguish "I mean the 6 ASCII
  chars" from "I mean the codepoint."
  2. Whole-string swap is all-or-nothing: The Edit tool's fallback tries two
  forms — all codepoints expanded, or all escapes preserved — but when the file
  has both in the same region, neither whole-string variant matches.
  3. The caller can't fix it: Since JSON normalizes the escape before the tool
  ever sees the parameter, no old_string value can express "line 3 has the
  codepoint, line 4 has the ASCII escape."

  ─────────────────────────────────────────────────

  Let me verify the file is unchanged and clean up.

● Bash(od -c /tmp/claude-edit-repro/recipes.ts | head -10)
  ⎿  0000000   /   /       S   a   m   p   l   e       d   e   s   s   e
     r
     0000020   t       p   r   i   c   e       r   a   n   g   e   s   .  \
     … +15 lines (ctrl+o to expand)

● File unchanged, confirmed.

  Summary: The bug from #52813 is still reproducible on the current version. The
  Edit tool fails when a multi-line old_string spans a region where the same
  Unicode character appears as both a literal codepoint and a \uXXXX source
  escape. The whole-string swap fallback tries "all literals" and "all escapes"
  but can't handle the mixed case. The workaround remains: use sed/node/bun via
  Bash for these edits.

✻ Sautéed for 1m 28s
❯ /feedback The bug from #52813 is still reproducible on the current version. The Edit tool fails when a multi-line old_string spans a region where the same Unicode character appears as both a literal codepoint and a \uXXXX source escape. The whole-string swap fallback tries "all literals" and "all escapes" but can't handle the mixed case. The workaround remains: use sed/node/bun via Bash for these edits. 
  ⎿  Feedback / bug report submitted

View original on GitHub ↗

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