[BUG] Claude clobbers correct typographic marks and can't be told otherwise
Environment
- Platform (select one):
- [x] Anthropic API
- [ ] AWS Bedrock
- [ ] Google Vertex AI
- [ ] Other: <!-- specify -->
- Claude CLI version: 1.0.11
- Operating System: macOS 15.3.1
- Terminal: ghostty
Bug Description
When suggesting significant edits to files, Claude will decide to "fix" already-correct typographic marks (and thus making them incorrect).
For example, I have a user-facing string in my code that says I’m, and Claude (when editing unrelated code) does a drive-by that replaces it with I'm. I've tried adding custom instructions in CLAUDE.md asking it to do the exact opposite (because I generally want to use the correct typographic marks!), but even though Claude can identify that it isn't following the rules, when trying to fix the issue, it justs spit out a bunch of the same error:
Error: No changes to make: old_string and new_string are exactly the same.
Steps to Reproduce
- Ask Claude to make significant changes to a file that has Unicode typographical marks in it (proper apostrophes/curly quotes)
- Claude will reduce a single apostrophe to a foot mark ('), and curly quotes to inch marks (").
Expected Behavior
Claude should not try to change the unrelated strings and leave them as they are. Ideally it would do the opposite in my case -- finding instances of user-facing text or comments that use the incorrect versions and update them accordingly.
Actual Behavior
Claude clobbers the correct code, forcing me to address the diff before committing the code.
18 Comments
I'm definitely also seeing this. When editing part of my code that had a curly apostrophe, it edited it to be straight apostrophe:
<img width="739" height="135" alt="Image" src="https://github.com/user-attachments/assets/c7291aef-6477-40f3-81f0-04a3e1de1e45" />
In this case, the _intended_ diff was simply adding
.name-of-Godto the two spans, but the apostrophes in the regex got caught up in the edit too.A key insight is that I really don't think this was the Claude model's fault, rather there must be some processing/filtering happening in some other layer of the Claude Code stack.
I discussed the issue with Claude Code, and we came up with a bug report (although, worth noting that of course, it can't render the curly apostrophes properly; mentions of
['']should be['’]):------------
Unicode Character Normalization Bug in Edit Tool
Description:
Claude Code's Edit tool appears to normalize Unicode characters during edit operations, converting curly/smart apostrophes
(U+2019 ') to straight apostrophes (U+0027 ') without user awareness.
Steps to Reproduce:
/\bLORD([''][sS])?\b/g(straight + curly)Expected Behavior:
Unicode characters should be preserved exactly as they appear in the original file.
Actual Behavior:
The Edit tool silently normalizes Unicode characters, changing
['']to[''](both straight apostrophes).Evidence:
apostrophes in text processing)
Impact:
This could affect any code that relies on specific Unicode characters, particularly:
Workaround:
Use Unicode escape sequences (e.g.,
\u2019) instead of literal Unicode characters.------------
I've not yet tested the workaround, but I imagine it'd work. Still really not optimal, however, especially as the model doesn't realize this current limitation, and will repeatedly trigger it. I really believe the model is actually sending
’, but it's being filtered/replaced/normalized by some other layer.Final remarks to Claude after it made the bug report:
------
And if there's any doubt that this is an issue with our terminals or configs, this issue does _not_ happen with Gemini CLI:
<img width="751" height="132" alt="Image" src="https://github.com/user-attachments/assets/fe84146c-a078-49ab-b9b9-632229d48a91" />
The diff is slightly different (the model solved the issue slightly differently), but you'll see that the apostrophes in the regex at the top remain unmodified.
When Claude is explicitly told to replace straight quotes with curly quotes, it goes into an edit error loop:
<img width="934" height="640" alt="Image" src="https://github.com/user-attachments/assets/21a805d4-b9f0-409e-923a-077bc591e28d" />
Confirming on Linux + Critical Impact in Perl
I can confirm this bug also affects Linux (Fedora 42), not just macOS. The impact in our Perl codebase was severe:
Impact
'(U+2019) to'(U+0027) breaks string literals:Affected Files
Workaround
Using
perl -i -peinstead of the Edit tool preserves UTF-8:Additional Context
This is a high-priority bug as it silently corrupts code in production. The Edit tool should preserve exact UTF-8 byte sequences.
We've documented this extensively in our migration lessons learned. Happy to provide more details if needed.
(human addendum: not even this comment formulated by claude seems to be able to use the correct utf8 characters)
Environment:
Description:
I am consistently experiencing an issue where UTF-8 characters are being "normalized" or stripped from the output. Specifically, Portuguese diacritics and accents (e.g.,
ç,ã,é,ô) are being replaced by their ASCII equivalents (e.g.,c,a,e,o) or lost entirely.Impact:
This is critical for my workflow as it is introducing regressions in production code, particularly affecting string literals, i18n files, and documentation.
This issue has been inactive for 30 days. If the issue is still occurring, please comment to let us know. Otherwise, this issue will be automatically closed in 30 days for housekeeping purposes.
Just tested it. It's still failing.
My prompt:
Code before:
Code after:
Rather than having your bot try to auto-close this, how about we have someone from Anthropic actually look at this issue and respond... if only to show that submitting bug reports isn't a waste of our time??
It's infuriating. Claude Code knows about typographic marks and thinks it's using them, but simply doesn't. Issue #18422 is a detailed bug report, but here's the simplest single step to reproduce, just prompt:
Complain and Claude Code will even claim _The opening quote is " (U+201C, LEFT DOUBLE QUOTATION MARK) and the closing quote is " (U+201D, RIGHT DOUBLE QUOTATION MARK)._ ... as it outputs straight ASCII 😠.
I pointed Claude Code at this bug report and it commented "there's a bug in Claude Code itself where Unicode typographic characters are being normalized to their ASCII equivalents somewhere in the processing pipeline before output reaches you. ... I was not aware of my own output being affected by this bug because I don't see what you see after the normalization layer processes it."
I run into the edit errors too when working with localization files. This is still happening as of Claude Code 2.1.31
Note that this isn't a Claude Code issue, this is a fundamental Claude issue. Happens in the web UI as well. Even Opus 4.6 still cannot tell the difference and confabulates that it's using the curly versions when it is not.
<img width="762" height="1037" alt="Image" src="https://github.com/user-attachments/assets/3f61ffcc-ba73-43c6-bdbf-1ab0e781c575" />
This issue was also tracked in #1986 (now auto-closed and locked), where a community workaround was proposed: a skill that uses a placeholder + sed/perl post-processing to restore curly apostrophes (U+2019) and curly quotes (U+201C/U+201D) after Write/Edit operations.
The skill is available here (French and English versions)
Current status of the problem (March 2026):
After 7+ months and multiple duplicate issues (#8234, #14355, #15920, #26141, #29786), this remains unresolved. Is there any plan to address this at the tool level, e.g. a preserveUnicode flag or context-aware normalization?
This issue perfectly captures the core problem: Claude’s Write/Edit tools normalize curly typographic characters to straight ASCII, destroying correct typography even when CLAUDE.md explicitly says otherwise.
I’ve filed a feature request proposing a solution: a
/curlyoption that replaces blind normalization with context-aware verification. The rule is simple: a curly character inside a straight delimiter is valid content (preserved); a curly character used as a delimiter is a syntax error (normalized). Two modes:/curly safe(doubt favors code) and/curly lazy(doubt favors typography).→ [FEATURE] /curly option: context-aware curly/straight character handling in Write/Edit — #31482
In the meantime, I’ve published reusable Claude Code skills as workarounds (placeholder substitution + perl post-processing). Happy to share if useful.
/tmp/issue-1599-answer.md
This appears to have been fixed with Opus 4.7. We've been able to remove our many work arounds (placeholder systems etc) as of this morning and editing/generation appears to be reliable.
Thanks Sihil,
I can confirm that this works since Opus 4.7.
The skills are no longer required.
They just broke it in the opposite direction. After an entire day of debugging broken code due to un-parseable typographical punctuation instead of ASCII-safe markup, I asked Claude itself:
"They have no syntactic function in any computational context. Introducing them into source, data, or script files is unconditionally wrong." Their own model knows it's doing the wrong thing, but it can't stop itself. These different styles both have their place; why is it so hard to work out a conditional?
@sihil Not fixed for me in Opus 4.7. It's a bug in something other than the model.
@bcherny Just curious, how many dozens of bug reports have to be filed before you folks pay attention to this? How is it that with the infinite tokens at your disposal you can't hand this to Claude and let it fix the bug?
The bug still exists in Chatbot as well as Claude Code, even when using Opus 4.7.
@aardvarkk also, you can check AWS Bedrock as well: that's what we use and we also have the problem.