Desktop app silently ignores ~/.claude/settings.json when the file has a UTF-8 BOM (JSON.parse SyntaxError, warn-level log only)

Status Open
Reported on v2.1.219
Maintainer reply None cached
Activity 0 comments · opened Jul 26, 2026

Summary

If ~/.claude/settings.json is saved as UTF-8 with a BOM, the desktop app fails to parse it and falls back to defaults for every user setting — silently. The only trace is a single warn line per read in main.log. Nothing surfaces in the UI, and /config keeps showing (and writing) values as if the file were being honoured.

What makes this particularly hard to notice is the asymmetry: the bundled CLI tolerates the BOM and reads the same file fine, so hooks and permissions from settings.json keep working normally. Only the app-side settings quietly stop applying.

On Windows a BOM is easy to introduce by accident — PowerShell 5.1's Out-File and Set-Content -Encoding utf8 both write UTF-8 with BOM, so any script or one-liner that edits settings.json corrupts it from the app's point of view.

Environment

  • Claude Desktop app on Windows 11 Pro (10.0.26200)
  • Bundled Claude Code 2.1.219
  • ~/.claude/settings.json written at some point by a PowerShell script

Evidence

The file, as it was:

$ head -c 16 ~/.claude/settings.json | xxd
00000000: efbb bf7b 0d0a 2020 2020 2265 6e61 626c  ...{..    "enabl

JSON.parse rejects the leading U+FEFF, and the app logs:

2026-07-17 02:51:35 [warn] [SettingsIo] Failed to read C:\Users\owner\.claude\settings.json (SyntaxError)

This repeated on every settings read for nine days without any user-visible symptom — 514 occurrences in a single rotated log file:

$ grep -c "SettingsIo] Failed to read" main2.log
514

Meanwhile the CLI parsed the very same file correctly throughout: the SessionStart hook defined only in that settings.json executed normally on every session start.

Stripping the three leading bytes fixed it, with no other change to the file:

before: efbbbf size 3913
after : 7b0d0a size 3910

Impact

Every app-side setting silently reverts to its default. In our case "remoteControlAtStartup": true had been set for weeks and was never actually applied — Remote Control simply did not arm at startup, and there was no way to tell from the UI that the setting was being ignored. theme, inputNeededNotifEnabled and agentPushNotifEnabled were equally inert.

Because /config reads and writes through the same broken path, toggling a setting appears to work and then has no effect, which sends users looking for a bug in the feature rather than in settings loading.

Reproduction

  1. powershell -c "Get-Content ~/.claude/settings.json | Out-File ~/.claude/settings.json -Encoding utf8" (PS 5.1 — adds a BOM)
  2. Restart the app, or just switch session focus.
  3. main.log shows [SettingsIo] Failed to read … (SyntaxError); all app-side settings are now at their defaults, with no UI indication.

Expected

  • Strip a leading BOM before JSON.parse in SettingsIo (the CLI already does the equivalent — the two readers should agree on what a valid settings file is).
  • If a settings file cannot be parsed, surface it to the user (a banner, or an entry in /doctor) instead of a single warn line in a log the user has no reason to open. Silently running on defaults is the worst outcome here.

View original on GitHub ↗