Found while making Lite's sample settings file real (#2418). It is the most serious thing that work turned up and it is in neither issue.
One trailing comma resets all 88 settings, silently
Both settings loaders swallow every exception and fall back to defaults:
catch { /* Use default */ } // App.xaml.cs, LoadDefaultTimeRange
catch { /* Use defaults */ } // App.xaml.cs, LoadAlertSettings
LoadAlertSettings wraps the whole JsonDocument.Parse plus all 88 TryGetProperty calls in that one try. So a single malformed character does not cost one setting — the parse throws before any key is read and every setting reverts to its default at once. Alert thresholds, SMTP configuration, webhook enablement, retention, theme, the lot.
And the app structurally cannot tell you
The loaders run before logging exists:
LoadDefaultTimeRange(); <- here
LoadAlertSettings(); <- and here
... 13 lines ...
AppLogger.Initialize(logDirectory);
So there is no log line, no dialog, and no way to add one without reordering startup. The user sees a Performance Monitor that has forgotten its configuration, with nothing anywhere explaining why, and the most likely next move is to reconfigure everything by hand — writing the defaults back over the file that still holds the real settings, at which point the original is gone.
This matters more now, not less. #2418 ships a documented reference precisely so people hand-edit settings.json, and hand-editing JSON is how you get a trailing comma. We are about to make the triggering action more common while the failure stays invisible.
What to do
The two halves are separable and the first is most of the value.
Report it. Capture the exception and surface it once logging exists — a deferred diagnostic the loader records and AppLogger.Initialize flushes is enough, and avoids reordering startup. A user who is told "settings.json could not be parsed at line 42, defaults are in use" can fix it in a minute.
Do not overwrite what you could not read. This is the part that turns an annoyance into data loss. If the parse failed, WriteSetting's next whole-document rewrite replaces a file whose contents were never understood. At minimum, copy the unreadable file aside (settings.json.unreadable-<timestamp>) before the first write, so the original is recoverable.
Worth considering, though it is a bigger change: distinguishing "file absent" (a legitimate first run — defaults are correct and silent) from "file present but unparseable" (never correct, always worth saying). The current code cannot tell those apart, which is why the silence looks reasonable in the code and is wrong in practice.
Related: #2418 (the sample that makes hand-editing likelier), #2413 (a key with no UI, so hand-editing is the only path).
Found while making Lite's sample settings file real (#2418). It is the most serious thing that work turned up and it is in neither issue.
One trailing comma resets all 88 settings, silently
Both settings loaders swallow every exception and fall back to defaults:
LoadAlertSettingswraps the wholeJsonDocument.Parseplus all 88TryGetPropertycalls in that one try. So a single malformed character does not cost one setting — the parse throws before any key is read and every setting reverts to its default at once. Alert thresholds, SMTP configuration, webhook enablement, retention, theme, the lot.And the app structurally cannot tell you
The loaders run before logging exists:
So there is no log line, no dialog, and no way to add one without reordering startup. The user sees a Performance Monitor that has forgotten its configuration, with nothing anywhere explaining why, and the most likely next move is to reconfigure everything by hand — writing the defaults back over the file that still holds the real settings, at which point the original is gone.
This matters more now, not less. #2418 ships a documented reference precisely so people hand-edit settings.json, and hand-editing JSON is how you get a trailing comma. We are about to make the triggering action more common while the failure stays invisible.
What to do
The two halves are separable and the first is most of the value.
Report it. Capture the exception and surface it once logging exists — a deferred diagnostic the loader records and
AppLogger.Initializeflushes is enough, and avoids reordering startup. A user who is told "settings.json could not be parsed at line 42, defaults are in use" can fix it in a minute.Do not overwrite what you could not read. This is the part that turns an annoyance into data loss. If the parse failed,
WriteSetting's next whole-document rewrite replaces a file whose contents were never understood. At minimum, copy the unreadable file aside (settings.json.unreadable-<timestamp>) before the first write, so the original is recoverable.Worth considering, though it is a bigger change: distinguishing "file absent" (a legitimate first run — defaults are correct and silent) from "file present but unparseable" (never correct, always worth saying). The current code cannot tell those apart, which is why the silence looks reasonable in the code and is wrong in practice.
Related: #2418 (the sample that makes hand-editing likelier), #2413 (a key with no UI, so hand-editing is the only path).