[BUG] Write drops an existing file's BOM, CRLF line endings and encoding (UTF-16LE, Windows-1252, Shift_JIS), while Edit keeps them or refuses

Status Open
Reported on v2.1.296
Maintainer reply None cached
Activity 0 comments · opened Oct 11, 2026

What's Wrong?

When Write overwrites an existing file, it saves the new content as UTF-8 with no BOM and LF line endings, whatever the file was before. Edit on the same files keeps the BOM, the CRLF line endings and UTF-16LE, and since 2.1.296 it refuses legacy encodings instead of re-encoding them. Write does none of this. Its result is the same "has been updated successfully" in every case, so neither the model nor the user learns that the file's format changed.

Measured on 2.1.296: seven existing files, the same one-word change (APPLE → ORANGE), once with Write and once with Edit.

| existing file | after Write | after Edit |
|---|---|---|
| UTF-8 with BOM, CRLF (.ps1) | BOM dropped, CRLF → LF | exact (only the word changed) |
| UTF-8, CRLF (.cmd, Japanese comment) | CRLF → LF | exact |
| ASCII, CRLF | CRLF → LF | exact |
| UTF-16LE with BOM, CRLF | BOM dropped (still UTF-16LE), CRLF → LF | exact |
| Windows-1252, CRLF | re-encoded as UTF-8, CRLF → LF | refused, file untouched |
| Shift_JIS, CRLF | re-encoded as UTF-8, CRLF → LF | refused, file untouched |
| UTF-8, LF (control) | exact | exact |

Each of these conversions has already caused a reported failure on its own:

  • BOM dropped from a .ps1: Windows PowerShell 5.1 reads the file in the ANSI code page, and the script mojibakes or fails to parse (#90962).
  • CRLF → LF on a .cmd: under a DBCS code page, cmd.exe can swallow the LF after a multibyte character. In #92328 that turned del /F /Q "%WORK%" into del /F /Q "" and deleted the files in the working directory.
  • UTF-16LE without a BOM: almost nothing detects it. Here PowerShell 5.1 Select-String -Pattern ORANGE no longer finds the word in the rewritten file, while it finds APPLE in the original with its BOM. UTF-16LE files are common on Windows because PowerShell 5.1's > and Out-File write it by default.
  • Legacy code page → UTF-8: this is why 2.1.296 made Edit refuse such files (#96263, #7134). Write on the same file still converts it silently.

The CRLF part was reported for Write in #64599 (June 2026). That issue was closed as stale and locked, not fixed.

What Should Happen?

When Write replaces an existing file, it should keep that file's BOM, line-ending style and encoding, as Edit does. Where it cannot write the original encoding, it should do what Edit now does: refuse and say why, or at least say in its result that the file was converted.

Steps to Reproduce

  1. Create seven files, each containing the word APPLE (/ marks a line break):

``
a_bom_crlf.ps1 UTF-8 with BOM, CRLF Write-Output "こんにちは" / $fruit = "APPLE" / Write-Output "さようなら"
b_crlf.cmd UTF-8, CRLF @echo off / rem 日本語のコメント。 / set FRUIT=APPLE
c_crlf.txt ASCII, CRLF line one / fruit = APPLE / line three
d_utf16le.txt UTF-16LE with BOM, CRLF メモ / fruit = APPLE / 終わり
e_cp1252.cs Windows-1252, CRLF // è già così / string fruit = "APPLE";
f_sjis.txt Shift_JIS, CRLF 日本語のメモ / fruit = APPLE
g_lf.txt UTF-8, LF line one / fruit = APPLE / line three
``

  1. Ask Claude to Read each file and Write it back with APPLE changed to ORANGE. I gave the full new content verbatim, with the real characters, so the model had nothing to guess.
  2. Check the bytes (BOM, CR count, encoding). Every Write call returned "The file … has been updated successfully."
  3. Control: in fresh copies, ask for the same change with Edit.

Byte counts, before → after Write / after Edit: .ps1 85 → 80 / 86, .cmd 61 → 59 / 62, ASCII CRLF 37 → 35 / 38, UTF-16LE 50 → 44 / 52, Windows-1252 40 → 42 / 40 (refused), Shift_JIS 29 → 34 / 29 (refused), LF control 34 → 35 / 35.

Environment

  • Claude Code 2.1.296, claude -p with Sonnet, --permission-mode acceptEdits. The Write run had Edit, Bash and PowerShell disallowed; the Edit run had Write, Bash and PowerShell disallowed.
  • Windows 11 Home 10.0.26200, ACP/OEMCP 932

Related: #90962, #92328, #7134, #96263, #64599 (closed as stale, locked).

View original on GitHub ↗