[BUG] Windows (CJK locale): permission rules with non-ASCII prefix never match; "Always allow" persists mojibake rules; backslashes double on every settings rewrite

Open 💬 0 comments Opened Jul 2, 2026 by zu5300-commits

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?

On a CJK-locale Windows machine (system ANSI codepage 950 / Big5, Traditional Chinese), the permission system mishandles non-ASCII characters end-to-end, producing three compounding failures:

  1. Allow rules whose command prefix contains CJK characters never match the byte-identical command, so every whitelisted script call prompts again. In our sessions the same whitelisted scripts prompted 5/5 times, and again 3/3 after an app restart + update.
  2. Clicking "Always allow" persists the rule into .claude/settings.local.json with the CJK bytes encoded in the ANSI codepage (Big5) instead of UTF-8 — the saved rule is mojibake inside an otherwise-UTF-8 file, can never match, and silently does nothing. Approving again just accumulates dead duplicates.
  3. Every time the app appends a new rule it re-serializes existing entries and doubles their backslashes (\\\\\\), progressively corrupting the file. Long-lived files contain entries with 4–6 backslashes and permanently lost CJK (U+FFFD replacement chars).

The defect is isolated to the rule side: an allow rule whose prefix is pure ASCII (e.g. PowerShell(Test-Path *)) silently matches a command whose arguments contain CJK paths — verified in the same session. Only rules whose prefix itself contains CJK never match.

Net effect: permission allowlists are unusable for any user whose paths contain Chinese/Japanese/Korean characters (the common case for zh/ja/ko users), and the file meant to remember approvals rots a little more with each approval.

Environment: Windows 11 Home 10.0.26200 · system locale zh-TW (ANSI codepage 950) · Claude Code desktop app v1.18286.0 (also reproduced on the build immediately before) · PowerShell 5.1 · project path contains CJK characters.

What Should Happen?

  • Rules and commands are compared as Unicode strings (ideally NFC-normalized), regardless of the machine's ANSI codepage — a rule containing 工作區 should match a command containing 工作區.
  • "Always allow" persists rules as UTF-8, byte-faithful to the approved command, so the approval is actually remembered.
  • Re-serialization of the settings file is idempotent — appending rule N must not mutate rules 1..N-1 (no backslash doubling).
  • If a stored rule contains invalid UTF-8 / U+FFFD or fails to parse, surface a warning instead of silently never matching.

Error Messages/Logs

Rule as written by "Always allow" into .claude/settings.local.json — the CJK folder name 工作區 was stored as ANSI/Big5 bytes, which render as mojibake when the file is read as UTF-8:

    "PowerShell(C:\\Users\\<USER>\\Documents\\claude�u�@��\\tools\\hello.ps1 -Source \"C:\\Users\\<USER>\\Documents\\claude�u�@��\\docs\\�}�o�F���@���s.md\")"

(�u�@�� is exactly the Big5 byte sequence A4 75 A7 40 B0 CF for 工作區 mis-decoded as UTF-8 — each invalid byte becomes U+FFFD.)

After clicking "Always allow" on any unrelated later command, previously saved entries in the same file are rewritten with doubled backslashes:

    before: "PowerShell(C:\\Users\\<USER>\\..."
    after:  "PowerShell(C:\\\\Users\\\\<USER>\\\\..."

Entries that have survived several rewrites show 4–6 backslashes per separator.

Steps to Reproduce

  1. Windows machine with system ANSI codepage 950 (Traditional Chinese locale; the same class of bug should reproduce with 932/936/949).
  2. Create a trivial script at a CJK path, e.g. C:\Users\<USER>\Documents\工作區\tools\hello.ps1.
  3. Add to ~/.claude/settings.jsonpermissions.allow: "PowerShell(C:\\Users\\<USER>\\Documents\\工作區\\tools\\hello.ps1 *)" (file saved as valid UTF-8; the CJK renders correctly when read back).
  4. Start a NEW session (settings load at session start). Ask Claude to run the script by full path — the command string is byte-identical to the rule prefix.
  5. BUG 1: a permission prompt appears anyway; repeats on every call.
  6. Click "Always allow", then open .claude/settings.local.json in a hex/UTF-8 editor.
  7. BUG 2: the newly saved rule's CJK segments are ANSI/Big5 bytes inside an otherwise-UTF-8 file (mojibake); the rule never matches; the next identical command prompts again.
  8. Trigger any unrelated approval so the app appends another rule.
  9. BUG 3: previously saved entries are rewritten with doubled backslashes (C:\\UsersC:\\\\Users).

Control probes (isolate the defect):

  • Get-Date -Format ... with ASCII rule PowerShell(Get-Date *) → no prompt (engine works).
  • Test-Path "C:\...\工作區\file.md" (CJK argument) with ASCII rule PowerShell(Test-Path *) → no prompt (command-side CJK is fine).
  • Only rules whose PREFIX contains CJK fail.

Mitigations already attempted (all verified, none helped): bare-path and & "..." rule forms; byte-identical calling convention; fresh session after every settings change; full app restart; applying the pending update; additionalDirectories including the CJK workspace; repeated "Always allow". Working workaround: an ASCII-only NTFS junction pointing at the CJK folder + ASCII-prefix rules.

Claude Model

None

Is this a regression?

Yes, this worked in a previous version

Last Working Version

exact number unknown — the build in use on 2026-07-02 (one update earlier): same CJK rules matched with zero prompts

Claude Code Version

2.1.186 (Claude Code) — Windows desktop app v1.18286.0

Platform

Anthropic API

Operating System

Windows

Terminal/Shell

PowerShell

Additional Information

Closely related existing issues (same defect family):

  • #46783 — Windows: permission prompt generates backslash allow-rules that never match forward-slash Bash commands (allow-rule written in a form that can never match — ours is the encoding variant)
  • #46486 — PowerShell output displays garbled text on Windows when system codepage is Big5 (950) (same CP950-vs-UTF-8 root cause, different surface)
  • #7332 / #7134 — encoding-handling class (garbled Chinese output; Windows-1252 file corruption)

Suggested fixes:

  1. Persist settings explicitly as UTF-8 on Windows (matching how the file is read); on read, tolerate and repair legacy ANSI bytes.
  2. Normalize both rule prefix and incoming command (NFC) before prefix matching; add a regression test with a CJK path on a CP950 runner.
  3. Make re-serialization idempotent (parse → modify → stringify through one JSON path); add a round-trip test asserting appended rules leave existing entries byte-identical.
  4. Surface dead rules: if a stored rule contains invalid UTF-8 / U+FFFD, warn in the permission UI instead of silently never matching.

Impact: autonomous pipelines built on full-path allowlists (fixed backup/test/convert scripts) are fully blocked for users with non-ASCII project paths; "Always allow" is a silent no-op for them and corrupts the settings file over time.

Full local session transcripts of 2026-07-03 available on request (5-prompt run, then 3-prompt run after restart+update; before/after copies of the corrupted settings.local.json).

View original on GitHub ↗