AutoDarkMode/Windows-Auto-Night-Mode · error · InvalidOperationException
Failed to deserialize JSON from file: {path}
Error message
Failed to deserialize JSON from file: {path} What it means
Thrown by FileService.Read<T>() when System.Text.Json cannot parse the contents of a local settings file. The method reads the file with File.ReadAllText, checks for blank content (returns default), then attempts JsonSerializer.Deserialize; any JsonException is caught and re-thrown as InvalidOperationException with the file path as context. It signals that a persisted JSON file exists but is syntactically invalid or does not match the target type T.
Source
Thrown at AutoDarkModeApp/Services/FileService.cs:37
var path = Path.Combine(folderPath, fileName);
if (!File.Exists(path))
{
return default;
}
var json = File.ReadAllText(path);
if (string.IsNullOrWhiteSpace(json))
{
return default;
}
try
{
return JsonSerializer.Deserialize<T>(json, _jsonOptions);
}
catch (JsonException ex)
{
throw new InvalidOperationException($"Failed to deserialize JSON from file: {path}", ex);
}
}
public void Save<T>(string folderPath, string fileName, T content)
{
if (!Directory.Exists(folderPath))
{
Directory.CreateDirectory(folderPath);
}
var fileContent = JsonSerializer.Serialize(content, _jsonOptions);
WriteAllTextWithRetry(Path.Combine(folderPath, fileName), fileContent);
}
public void Delete(string folderPath, string fileName)
{
if (fileName != null && File.Exists(Path.Combine(folderPath, fileName)))
{View on GitHub (pinned to c15b28e921)
Solutions
- Open the file at the reported {path} and validate its JSON (e.g. with a linter); fix or delete it so the app regenerates defaults.
- Delete the corrupt file entirely — Read<T> returns default when the file is absent, letting the app rebuild it.
- Ensure Save() writes atomically (write to a temp file then File.Move/replace) to prevent partial writes from crashes.
- Verify the file encoding is UTF-8 without BOM issues and that the JSON matches the current type T schema after upgrades.
Example fix
// before (FileService.Save — non-atomic, truncates on crash) var fileContent = JsonSerializer.Serialize(content, _jsonOptions); WriteAllTextWithRetry(Path.Combine(folderPath, fileName), fileContent); // after — write temp then atomic move so a crash cannot leave a truncated file var temp = Path.Combine(folderPath, fileName + ".tmp"); File.WriteAllText(temp, fileContent, Encoding.UTF8); if (File.Exists(path)) File.Replace(temp, path, null); else File.Move(temp, path);
Defensive patterns
Strategy: try-catch
Validate before calling
// Pre-validate the file is parseable JSON before deserializing into T
public static bool TryValidateJson(string path)
{
if (!File.Exists(path)) return true; // absent is fine, Read returns default
var json = File.ReadAllText(path);
if (string.IsNullOrWhiteSpace(json)) return true;
try { using var doc = JsonDocument.Parse(json); return true; }
catch (JsonException) { return false; }
} Type guard
// Type guard for callers of FileService.Read<T>
if (fileService.Read<MySettings>(folder, file) is { } settings)
{
// settings deserialized successfully
}
else
{
// file missing, blank, or returned default — apply defaults
} Try / catch
try
{
var settings = fileService.Read<MySettings>(folder, file);
}
catch (InvalidOperationException ex) when (ex.InnerException is JsonException)
{
// corrupt settings file — back it up and let the app regenerate defaults
File.Move(path, path + ".corrupt");
} Prevention
- Write settings atomically (temp file + File.Replace) so a crash cannot leave a truncated JSON file.
- Exclude the settings directory from AV/cloud-sync real-time scanning that can lock or partially rewrite files.
- After an app upgrade that changes type T, add a migration/version field so old files deserialize or are reset cleanly.
- Never hand-edit settings JSON; if you must, validate with a JSON linter before saving.
When it happens
Trigger: Calling IFileService.Read<T>(folderPath, fileName) where the file at Path.Combine(folderPath, fileName) contains malformed JSON (truncated, invalid syntax, wrong types). The JsonSerializer.Deserialize<T> call throws JsonException which is wrapped at FileService.cs:37.
Common situations: App crash or power loss during Save() truncates a settings JSON file; antivirus or sync tools (OneDrive) lock and partially rewrite the file; a user manually edits a settings file and introduces a syntax error; an app upgrade changed the type T so an old file no longer deserializes cleanly.
Related errors
AI-assisted analysis of AutoDarkMode/Windows-Auto-Night-Mode@c15b28e921 (2026-08-13).
Data as JSON: /api/errors/c178f06b386f2f40.
Report an issue: GitHub.