Skip to content

A malformed settings.json silently resets all 88 Lite settings, before logging exists to say so #2425

Description

@erikdarlingdata

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).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions