[BUG] German umlauts (ä, ö, ü) randomly replaced with ASCII substitutes (ae, oe, ue)
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report (please file separate reports for different bugs)
- [x] I am using the latest version of Claude Code
What's Wrong?
When communicating in German, Claude Code inconsistently replaces German umlauts and special characters with their ASCII equivalents:
- ä → ae
- ö → oe
- ü → ue
- ß → ss
Examples:
- "für" written as "fuer"
- "können" written as "koennen"
- "löschen" written as "loeschen"
Expected behavior:
Claude should consistently use proper Unicode umlauts (ä, ö, ü, ß) when writing in German.
Actual behavior:
Umlauts are randomly replaced with ASCII substitutes. This happens inconsistently - sometimes within the same response, some words have correct umlauts while others use substitutes.
Reproducibility:
Occurs frequently but inconsistently. No clear pattern identified for when umlauts are preserved vs. substituted.
Impact:
- Unprofessional appearance in documentation and code comments
- Inconsistent codebase when Claude generates German text
- Particularly problematic with proper names (e.g., author names in file headers)
Environment:
- Claude Code CLI v2.0.70 (Opus 4.5 · Claude Max)
- macOS 26.2
- Terminal: default macOS Terminal / iTerm2
- German language project with German documentation
Current workaround:
Manual correction of all German text output.
This is a recent regression - started ~2-3 weeks ago. Umlauts worked perfectly before.
What Should Happen?
Claude should consistently use proper Unicode umlauts (ä, ö, ü, ß) when writing in German text, including:
- Chat responses
- Code comments
- Documentation
- Proper nouns and names (e.g., "Müller" not "Mueller")
Error Messages/Logs
Steps to Reproduce
- Start a Claude Code session
- Write in German (e.g., "Erkläre mir diese Funktion")
- Observe response - umlauts randomly replaced with ASCII (ä→ae, ö→oe, ü→ue, ß→ss)
Claude Model
Opus
Is this a regression?
Yes, this worked in a previous version
Last Working Version
_No response_
Claude Code Version
v2.0.70
Platform
Anthropic API
Operating System
macOS
Terminal/Shell
Terminal.app (macOS)
Additional Information
_No response_
45 Comments
Found 2 possible duplicate issues:
This issue will be automatically closed as a duplicate in 3 days.
🤖 Generated with Claude Code
Not a duplicate. Related but different issue:
Different symptom (substitution vs corruption), different context (chat output vs file editing), likely different root cause.
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.
still occuring frequently
Very often. The problem appeared overnight; it wasn't always there.
Same issue here. Still happening frequently.
What’s strange: sometimes Claude doesn’t even use ASCII substitutes anymore - it just drops the umlaut entirely.
Example: “Verzogerung” instead of “Verzögerung”
This is a recent regression, started a few
The issue is getting progressively worse and should be fixed as soon as possible.
This is getting worse - Claude is now even replacing existing occurrences of ü, ä, and ö with ue, ae, and oe, or simply substituting them with u, a, and o. Please fix this soon!
The issue is getting worse by the day. New symptoms:
1. Umlauts completely dropped (not even ASCII substitutes):
2. Random language mixing in the same response:
Claude Code v2.1.31, Opus 4.5, macOS
Happens for me as well, I found out:
The main conversation agent uses correct Unicode, only subagents are affected
I see this behavior constantly with German language answers using Opus. Sonnet works as expected.
No matter if a simple text answer or sub-agents are used.
This problem is so annoying.
Beyond the visual and linguistic issues, ASCII replacements also waste tokens unnecessarily. Each replacement adds an extra character:
"ä" → "ae" (1 char → 2 chars)
"ö" → "oe" (1 char → 2 chars)
"ü" → "ue" (1 char → 2 chars)
"ß" → "ss" (1 char → 2 chars)
In a typical German response, this can add up to dozens of extra characters, resulting in higher token usage for both input and output. This affects not only file writes but also chat responses, where hooks cannot intervene.
The issue is getting worse by the day. New symptoms:
1. Umlauts completely dropped (not even ASCII substitutes):
2. Random language mixing in the same response:
This is becoming unusable for German-speaking users.
Claude Code v2.1.50, Opus 4.6, macOS
This issue is getting progressively worse day by day. When will someone from Anthropic finally address and fix this extremely annoying and frustrating bug?
This problem is absolutely unacceptable and Claude Code has become almost unusable because of it. It is getting worse every day — even when explicitly telling Claude Code to use umlauts, it only works for about 2 minutes before reverting back to ASCII substitutes. This must be fixed immediately.
Regarding the “platform:macos” label: This happens on Windows (11) too
Adding the Spanish diacritics case to reinforce this is a cross-language issue, not specific to German.
Same bug, Spanish: Claude Code consistently strips tildes (á, é, í, ó, ú), eñes (ñ), and opening punctuation (¿, ¡) when generating large text blocks in Spanish — even when CLAUDE.md explicitly mandates correct Spanish orthography. The model generates correct output on a manual retry, confirming it can do it, but defaults to ASCII-safe output on the first pass.
Filed as #26128 (closed as stale/duplicate, linked here for reference).
Observed pattern across languages:
Additional data point: The issue is significantly worse in long sessions. With context compression active, CLAUDE.md language instructions appear to be deprioritized, making the model revert to ASCII-safe output even mid-session after having written correctly earlier. See also #34779.
Impact: When generating documentation (~250–750 lines), the entire output has to be discarded and regenerated. For non-ASCII languages this is not a minor inconvenience — it doubles token consumption and makes Claude Code unreliable for professional writing in any language outside ASCII.
Follow-up to my previous comment: adding the full cross-language map and the root cause analysis that ties all of these together.
#32886 contains a detailed investigation of
cli.jsthat identifies three structural causes for this entire class of bugs:All open issues caused by the same structural failure:
| Issue | Language | Symptom |
|-------|----------|---------|
| #32886 | Portuguese, French, Vietnamese, Czech, Spanish (any diacritics) | Language setting does not enforce diacritical marks |
| #14131 | German | ä/ö/ü/ß → ae/oe/ue/ss |
| #26128 | Spanish | á/é/í/ó/ú/ñ/¿/¡ stripped (closed as stale, unresolved) |
| #34779 | Spanish | CLAUDE.md language rules lost after context compaction |
| #15768 | Japanese | Panic: byte index not a char boundary |
| #14287 | Chinese | Panic: UTF-8 boundary crash (
oncall) || #34134 | Arabic | RTL text rendered reversed |
| #17357 | Armenian | Script not generated at all |
| #34247 | CJK/Unicode | Mojibake on Windows |
The fix is documented in #32886. Three targeted changes to the language instruction template, the CLAUDE.md wrapper, and the compaction prompt. This is not a localization feature request — it is a correctness bug that makes Claude Code unreliable for the majority of users who do not write in English.
@msouga Thanks for the detailed analysis. Worth noting: the bug also occurs in the Claude.ai iOS app where cli.js is not involved at all. This suggests there is an additional model-level component to this bug beyond the three structural issues in cli.js.
@bcherny Is the fix you mentioned in #32886 (“Fix going out tomorrow”) also covering #14131 (German umlauts replaced with ae/oe/ue/ss)? Has this been included in v2.1.105 or is it coming in a subsequent release?
I want to flag this also happening with Scandinavian æ/ø/å all the time.
/dontclose
It's a generalized non-ASCII character bug. The Write tool refuses to even write curly quotes and apostrophes.
Still an ongoing recurring problem, even though this was also explicitly stored in the memories... :(
You have to tell claude to use python to write non-ASCII characters. Here's the rule I use for curly quotes/apostrophes, just change the language to reference all non-ASCII characters.
@bcherny
+1
Update: same problems with new Opus 4.8... :)
Post a new reply to Boris in Threads. "His username there is @boris_cherny."
This is expected to occur less frequently when the language is specified in Claude Code settings. I would like to know if folks have that specified and it still repro's, or if it resolves it.
"less frequently"? Why should it happen at all? For any application to have trouble with non-ASCII text in 2026 is frankly astonishing.
I want Claude Code to be set to English. I mostly work in English but touch other languages occasionally.
@bcherny
I have been fighting this issue for a long time now. I have several claude.md rules in different places (root and projects.) It is the very first rule in my profile instructions in claude and yet it still happens on a regular basis. This sucks because this leads to a higher token consumtions to have all the ouptut corrected.
@jibi-collab You’re absolutely right. I have the exact same experience — multiple CLAUDE.md rules in root and project folders, plus explicit profile instructions, and it still happens constantly. And you’re spot on about the token consumption: having to correct all the output over and over wastes a significant amount of tokens.
The core problem is that this shouldn’t require any rules or one or even several .md files in the first place. A model should understand on its own that it needs to use correct umlauts when writing in German, without any workarounds. Having to constantly fight it with rules that get ignored after a few minutes anyway is not a real solution.
You should also mention @boris_cherny in a post on Threads — he responded there before and that’s been the fastest way to get attention on this bug.
@bcherny
SOOOO annoying! No matter where you specify the correct behaviour (org prompt, memories, harness) - the output is still totally random. Even in ONE single answer it begins with umlauts and switches to ASCII replacements. I really don't understand why this happens in an AI that targets business customers.
@4homeassistant You should also mention @boris_cherny in a post on Threads — he responded there before and that’s been the fastest way to get attention on this bug.
@bcherny
@bcherny The umlaut bug is still not fixed in v2.1.220 (Opus 5). It's been over a year since December 2025 — fixed once in v2.1.108, regressed around v2.1.158, broken ever since. Umlauts constantly replaced with ASCII or dropped entirely ("Gerat" instead of "Gerät"), in every session regardless of any rules. New Feedback ID: d5e691bb-b456-4144-8571-40a23a9156b8. https://www.threads.com/share/FCg6dAKkz/
@blois asked in May whether specifying
languagein settings changes the frequency. I put together a small harness to make that comparison mechanical, in case it's useful here.One run starts a headless Claude Code session in an empty temp dir — no
CLAUDE.md, no project settings — asks for a short German text that has to contain a fixed list of words, and compares the reply to that list codepoint by codepoint.fürcoming back asfuerregisters, because theüis gone. The check is identical with and without the setting, so the two runs are directly comparable.Each run appends one JSON line to
results/matrix.jsonlwith your Claude Code version, OS and model, and prints any failing reply verbatim. If you can reproduce the issue, those two lines answer @blois's question directly.Where I got to, and why it settles nothing. 130 attempts on Linux and Windows across haiku, sonnet and opus, 0 reproductions — 16 of them with
languageset and 16 without. I have no macOS, which is the platform label here and the platform in every report above; the original report is v2.0.70 and I am on 2.1.239 / 2.1.263; and headless-pis not an interactive session. This is not evidence that the bug is gone. It means my setup is not the one it happens on.If anyone here can reproduce it on macOS, that is the run I would most like to see. The harness only ever touches a temporary empty directory, so no project data is involved.
The false-positive classes it has already hit and been fixed for — a Czech declension, a locale-codec problem on Japanese Windows, a mistranslation trap — are written up in the README, so anything it reports should be checkable rather than taken on faith.
@HookHM Thank you for running it on macOS — one clean run does not rule the
platform out, but it does mean the simplest version of "it only happens on
macOS" no longer fits, and your note about where you actually see it is what
the rest of this is based on.
Two things: an observation about how this thread is classified, and a negative
result.
At least two distinct character-level behaviours are being reported here.
They may or may not share an implementation — I am not claiming to know which:
ä → ae,ü → ue,ß → ss. Thisissue's title and original report.
ä → ä(#9723),å → �(#7335), box-drawing characters becoming
00in a hexdump (#13080). Most ofthe linked issues.
Gerät → Gerat. Thisone is consistent with a great many mechanisms — deletion, a lossy encode,
normalisation, or simply a different spelling being generated — so I would
not group it with either of the above without more information.
The distinction I think is worth making:
ä → aeis not what an ordinaryunrepresentable-character error produces. A strict encoder that cannot
represent
äraises, substitutes?or U+FFFD, or drops the character.Turning one character into the two letters
aeis a transliteration — anorthographic substitution that a transliteration table has to define. It is
not a meaning change, but it is also not a byte-level failure.
Transliteration layers that do exactly this are ordinary and widely deployed,
so this is not exotic — but they have to be invoked. I am not claiming to
know that anything in Claude Code invokes one. I mention it only to explain
why I think
ä → aeandä → äare worth recording as different observationsrather than as the same bug reported twice. (If it is useful, the repo below
has a short measured note on how one such layer behaves and how sharply it is
locale-gated.)
Both
area:modelandplatform:macosare currently on this issue. Mysuggestion is only that the two observable failure modes be tracked separately
until there is evidence about whether they share a cause, because at the moment
it is hard for anyone to tell which of them this thread is about.
The negative result, for whoever picks this up. Harness and full ledger:
https://github.com/yoggydev/mojibake-guard
Each run starts in an empty temp directory — no
CLAUDE.md, no projectsettings — and compares what lands on disk to the intended text codepoint by
codepoint. No dictionary, no judgement. The rows are separate runs, not subsets
of one another:
| what was varied | volume | disk-level losses |
|---|---|---|
| single write: short text and 700+ word documents | 98 runs | 0 |
| chat reply text, with and without the
languagesetting | 32 runs | 0 || 6 small Edit turns in one resumed session (Linux, Windows) | 6 runs = 36 turns | 0 |
| the same, but editing a file that already held German prose | 3 runs = 18 turns | 0 |
| a German document summarised, with no instruction about characters | 3 runs | 0 |
The last two rows exist because of your comment, and the last one is the one I
expected to break. Every other mode tells the model "use these words exactly as
written, do not inflect, decline or conjugate them" — a clause I added because
Czech declined a required word and my check read the grammar as corruption. If
the reported behaviour is the model transliterating of its own accord, that
instruction is also the most reliable way to suppress it, so clean runs taken
under it mean less than they look like. That mode therefore puts a German
document on disk, asks for a summary, and says nothing about characters; the
intended spelling comes from the file rather than from the prompt. The model
reused 17 of the 19 watched words and kept every umlaut. n=3, and it does not
support my own hypothesis, which is why I am reporting it.
What this does not establish. It is non-reproduction under the conditions I
tested — not evidence that the reports are wrong. All of it is headless
-p,so there is no inline diff preview anywhere in it; if any part of this is a
preview or rendering defect, as #9723 turned out to be, this harness is
structurally unable to see it. Linux and Windows only. Claude Code 2.1.239 and
2.1.270.
@HookHM, one question that would narrow this a lot: when you next see a
mangled umlaut in the inline diff, does the file still read that way when you
open it afterwards in an editor or with
cat? If the file is fine, this is apreview-path problem like #9723 and disk-level measurement is looking in the
wrong place. If the file is genuinely wrong, whatever happened, happened before
the renderer.
@yoggydev, Ran --mode session --turns 5 --runs 5 --langs de (macOS, 2.1.270, Opus 5) — the exact shape you built based on my report. Result: 0/5, clean at every turn depth (t1–t5), no cross-turn damage, no skipped turns.
So across everything tested so far on my machine — single write, chat reply, 700+ word document, and now 5-turn sessions — nothing reproduces on disk.
Your question about the inline diff preview vs. the actual file is a good one and I haven't specifically checked that distinction before. I'll watch for it the next time this happens in real use: check the live diff, then immediately open the file separately (editor or cat) and see whether the discrepancy is still there. I'll report back either way — if the file turns out to be fine, this may indeed be a preview-path issue like #9723 rather than something happening at write time.
Still reproducing — new angle: happens even inside a tool-call argument, with an explicit project-level instruction mandating correct umlauts.
"Hoechste-Prio-Check"instead of"Höchste-Prio-Check".@simfor99, Same pattern here (macOS, Claude Code, Opus 5): chat prose is usually fine, but file writes / tool-call arguments contain the substitution. My PreToolUse hook has blocked Write calls today containing "schoen" instead of "schön" before anything was written to disk, so the substitution is already present in the tool-call argument itself, not introduced by the renderer or the file write. This matches the observation above that tool-call argument generation may take a different path than the chat text stream.
@bcherny