Skip to content

[BUG] Write tool saves files as UTF-8 without BOM, causing encoding corruption in Windows development tools (Delphi IDE, SSMS) #28316

Description

@jorgeb77

Preflight Checklist

  • I have searched existing issues and this hasn't been reported yet
  • This is a single bug report (please file separate reports for different bugs)
  • I am using the latest version of Claude Code

What's Wrong?

Summary

The Write tool in Claude Code saves all generated files (.pas, .dfm, .sql, and others) as UTF-8 without BOM (Byte
Order Mark). On Windows, many development tools default to ANSI/Windows-1252 when no BOM is present, causing silent data corruption of any non-ASCII characters in the generated files.

Environment

  • OS: Windows 11 Pro
  • Shell: bash (Git Bash / MSYS2)
  • Affected tools: Delphi 12 Athens IDE, SQL Server Management Studio (SSMS) 19+
  • Claude Code version: 2.1.51

Steps to Reproduce

Scenario A — Delphi source file (.pas)

  1. Ask Claude Code to create a .pas file containing a Spanish/accented string literal, e.g.:
    MessageBox(0, '¿Desea continuar?', 'Confirmación', MB_YESNO);
  2. Claude Code creates the file as UTF-8 without BOM (verifiable with a hex editor: no EF BB BF prefix).
  3. Open the .pas file in Delphi 12 Athens IDE.
  4. Delphi reads the file as ANSI (Windows-1252) because there is no BOM.
  5. Result: The string renders as ¿Desea continuar? / Confirmación at runtime.

Scenario B — SQL script (.sql)

  1. Ask Claude Code to create a .sql file with Unicode string literals:
    INSERT INTO TABLE VALUES (N'Día de Año Nuevo');
  2. Claude Code saves the file as UTF-8 without BOM.
  3. Open and execute the script in SSMS.
  4. SSMS reads the file as ANSI; the UTF-8 byte sequences for í (0xC3 0xAD) are interpreted as two Latin-1 characters
    (Ã + soft-hyphen).
  5. Result: The database stores DÃa de Año Nuevo — even though the correct N'' Unicode prefix is present.

Scenario C — Delphi form file (.dfm)

  1. Ask Claude Code to create a .dfm file with a caption containing accented characters:
    Caption = 'Médicos'
  2. Claude Code saves as UTF-8 without BOM.
  3. Delphi compiles the form reading the DFM as ANSI.
  4. Result: The caption renders as Médicos at runtime.

Root Cause

Files written by the Write tool are encoded as UTF-8 without BOM. On Windows, tools that do not implement encoding auto-detection fall back to the system ANSI code page (Windows-1252 / CP1252). The multi-byte UTF-8 sequences for characters above U+007F are then interpreted as multiple single-byte Latin-1 characters, producing garbled text that is silently written to the file, database, or compiled binary.

Expected Behavior

One of the following:

  1. (Preferred) The Write tool adds a UTF-8 BOM (EF BB BF) to text files on Windows, matching the default behavior of
    Delphi 12, Visual Studio, and most Windows-native editors.
  2. The Write tool exposes a parameter to control the output encoding (e.g., encoding: "utf-8-bom" | "utf-16-le" |
    "utf-8").
  3. The Write tool detects the file extension and applies the appropriate encoding for well-known formats that expect
    BOM on Windows (.pas, .dfm, .dpr, .sql, .cs, .vb, etc.).

Actual Behavior

All files are saved as UTF-8 without BOM regardless of extension, platform, or content.

Impact

  • Silent corruption: No error or warning is shown during file creation.
  • Hard to diagnose: The files look correct when viewed in UTF-8-aware editors (VS Code, Notepad++) but fail in tools
    that default to ANSI.
  • Affects Windows developers using any IDE or tool that relies on BOM for encoding detection: Delphi, RAD Studio,
    Visual Studio (legacy projects), SQL Server Management Studio, classic Notepad, etc.

Workaround (current)

Use #NNN escape notation for all non-ASCII characters in Delphi string literals (encoding-agnostic):
// Instead of: '¿Desea continuar?'
// Use: #191'Desea continuar?'
For SQL, use NCHAR() function or ensure the file is re-saved as UTF-16 in SSMS before execution.

What Should Happen?

You must save the accented characters correctly.

Error Messages/Logs

Steps to Reproduce

Steps to Reproduce

Prerequisites

  • Windows 10 or Windows 11
  • Claude Code installed
  • A hex editor or the PowerShell command Format-Hex (built into Windows)

Reproduce in 3 steps (minimal example)

  1. Ask Claude Code to create a file containing non-ASCII characters:

Use this exact prompt in Claude Code:

Create a file called test_encoding.pas with this exact content:

unit test_encoding;
interface
implementation
procedure Test;
begin
ShowMessage('¿Cómo estás? Día de Año Nuevo');
end;
end.

  1. Inspect the file encoding with PowerShell:

Open PowerShell and run:

Check the first 4 bytes of the file (BOM detection)

Format-Hex "test_encoding.pas" | Select-Object -First 1

Expected output (UTF-8 with BOM):
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
00000000 EF BB BF 75 6E 69 74 20 74 65 73 74 5F 65 6E 63 unit test_enc
(First 3 bytes must be EF BB BF — the UTF-8 BOM)

Actual output (UTF-8 without BOM):
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
00000000 75 6E 69 74 20 74 65 73 74 5F 65 6E 63 6F 64 69 unit test_encodi
(No BOM — file starts directly with 75 = u)

  1. Verify the corruption in a Windows tool:

Open test_encoding.pas in Notepad (not Notepad++, not VS Code — plain notepad.exe) and observe:

  • Expected: '¿Cómo estás? Día de Año Nuevo'
  • Actual: '¿Cómo estás? DÃa de Año Nuevo'

Reproduce the SQL corruption (real-world impact)

  1. Ask Claude Code to create a SQL file:

Create a file called test_unicode.sql with this content:

USE master;
INSERT INTO test_table (nombre) VALUES (N'José García');
INSERT INTO test_table (nombre) VALUES (N'Año Nuevo');

  1. Check encoding:
    Format-Hex "test_unicode.sql" | Select-Object -First 1
    (Same result: no BOM — first bytes are 55 53 45 = USE)

  2. Open and execute in SSMS:

  • Open the file in SQL Server Management Studio (File → Open → File...)
  • SSMS status bar will show "ANSI" encoding (not UTF-8)
  • Execute the script
  • Query the table: SELECT * FROM test_table
  • Result: José GarcÃa / Año Nuevo stored in the database — data permanently corrupted despite the correct N''
    Unicode prefix

Reproduce the Delphi Form file (.dfm) corruption

  1. Ask Claude Code to create a .dfm file:

Create a file called test_form.dfm with this exact content:

object TestForm: TTestForm
Caption = 'Gestión de Médicos'
object Label1: TLabel
Caption = 'Dirección:'
end
object Label2: TLabel
Caption = 'Año de nacimiento:'
end
object Label3: TLabel
Caption = 'Número de cédula:'
end
end

  1. Check encoding:
    Format-Hex "test_form.dfm" | Select-Object -First 1
    (Result: no BOM — file starts with 6F 62 6A = obj)

  2. Verify the corruption in Notepad:

Open test_form.dfm in plain notepad.exe:

  • Expected: Caption = 'Gestión de Médicos'
  • Actual: Caption = 'Gestión de Médicos'
  1. Real-world impact in Delphi 12:

When Delphi compiles this .dfm reading it as ANSI, the captions render at runtime as:

  • Gestión de Médicos (form title)
  • Dirección: (label)
  • Año de nacimiento: (label)
  • Número de cédula: (label)

One-liner verification (no extra tools needed)

Ask Claude Code to write any file with accented characters, then run:

$bytes = [System.IO.File]::ReadAllBytes("test_encoding.pas")
if ($bytes[0] -eq 0xEF -and $bytes[1] -eq 0xBB -and $bytes[2] -eq 0xBF) {
Write-Host "PASS: UTF-8 with BOM" -ForegroundColor Green
} else {
Write-Host "FAIL: UTF-8 without BOM (first bytes: {0:X2} {1:X2} {2:X2})" -f $bytes[0], $bytes[1], $bytes[2]
-ForegroundColor Red
}

Output: FAIL: UTF-8 without BOM (first bytes: 75 6E 69)

Claude Model

Sonnet (default)

Is this a regression?

I don't know

Last Working Version

No response

Claude Code Version

2.1.51

Platform

Other

Operating System

Windows

Terminal/Shell

PowerShell

Additional Information

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    duplicateThis issue or pull request already exists

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions