{"record":{"id":"e31ec4c4235bf139","repo":"mgth/LittleBigMouse","slug":"unterminated-border-resistance-side","errorCode":null,"errorMessage":"Unterminated border resistance side.","messagePattern":"Unterminated border resistance side\\.","errorType":"exception","errorClass":"JsonException","httpStatus":null,"severity":"error","filePath":"LittleBigMouse.Plugins/LittleBigMouse.Plugins.Core/Persistence/BorderSideDtoJsonConverter.cs","lineNumber":79,"sourceCode":"                case nameof(BorderSideDto.MoveBlock):\n                    dto.MoveBlock = ReadNullableBool(ref reader);\n                    break;\n                case nameof(BorderSideDto.Drag):\n                    dto.Drag = ReadNullableDouble(ref reader);\n                    break;\n                case nameof(BorderSideDto.DragBlock):\n                    dto.DragBlock = ReadNullableBool(ref reader);\n                    break;\n                case nameof(BorderSideDto.Sections):\n                    dto.Sections = JsonSerializer.Deserialize<List<BorderSectionDto>>(ref reader, options);\n                    break;\n                default:\n                    reader.Skip();\n                    break;\n            }\n        }\n\n        throw new JsonException(\"Unterminated border resistance side.\");\n    }\n\n    public override void Write(Utf8JsonWriter writer, BorderSideDto value, JsonSerializerOptions options)\n    {\n        writer.WriteStartObject();\n\n        if (value.Move is { } move) writer.WriteNumber(nameof(BorderSideDto.Move), move);\n        if (value.MoveBlock is { } moveBlock) writer.WriteBoolean(nameof(BorderSideDto.MoveBlock), moveBlock);\n        if (value.Drag is { } drag) writer.WriteNumber(nameof(BorderSideDto.Drag), drag);\n        if (value.DragBlock is { } dragBlock) writer.WriteBoolean(nameof(BorderSideDto.DragBlock), dragBlock);\n\n        if (value.Sections is { Count: > 0 } sections)\n        {\n            writer.WritePropertyName(nameof(BorderSideDto.Sections));\n            JsonSerializer.Serialize(writer, sections, options);\n        }\n\n        writer.WriteEndObject();","sourceCodeStart":61,"sourceCodeEnd":97,"githubUrl":"https://github.com/mgth/LittleBigMouse/blob/7a42f01d47d99d223b8ee33ba4019af82adf1c48/LittleBigMouse.Plugins/LittleBigMouse.Plugins.Core/Persistence/BorderSideDtoJsonConverter.cs#L61-L97","documentation":"After reading the initial token, Read loops through the object's members until it encounters EndObject. If the JSON stream ends (Read returns false) before the closing brace of the border-resistance-side object, the converter throws this JsonException. It indicates the serialized object was never closed.","triggerScenarios":"Deserializing truncated JSON such as {\"left\": {\"resistance\": 5 with no closing braces, typically from a partially written or cut-off settings file.","commonSituations":"Settings file corrupted by an app crash or power loss mid-write, file truncated by sync/disk issues, or manual editing that dropped closing braces.","solutions":["Validate the JSON file with a parser (e.g. JSON lint) and add the missing closing braces.","Restore the settings file from backup or delete it so the app recreates defaults.","Enable atomic writes (write temp file then rename) in whatever code persists these settings to avoid truncation.","Catch JsonException during load and fall back to a freshly generated default config."],"exampleFix":"// before (truncated)\n{ \"left\": { \"resistance\": 5\n// after\n{ \"left\": { \"resistance\": 5 } }","handlingStrategy":"try-catch","validationCode":"// verify JSON is well-formed before deserializing\ntry { using var _ = System.Text.Json.JsonDocument.Parse(json); }\ncatch (JsonException) { json = \"{}\"; /* rebuild defaults */ }","typeGuard":"static bool IsCompleteJson(string s)\n{\n    try { using var _ = System.Text.Json.JsonDocument.Parse(s); return true; }\n    catch (JsonException) { return false; }\n}","tryCatchPattern":"try\n{\n    dto = JsonSerializer.Deserialize<BorderSideDto>(json, options);\n}\ncatch (JsonException ex) when (ex.Message.Contains(\"Unterminated\"))\n{\n    Log.LogWarning(\"Settings JSON truncated; regenerating defaults.\");\n    dto = new BorderSideDto();\n}","preventionTips":["Persist settings atomically: write to a temp file then File.Move/replace.","Never hand-edit config files without re-validating with a JSON parser afterward.","Keep a known-good backup of the settings file and restore it when parsing fails."],"tags":["json","deserialization","truncated-file","custom-converter"],"backgroundTag":"json-parse-error","analyzedSha":"7a42f01d47d99d223b8ee33ba4019af82adf1c48","analyzedAt":"2026-09-16T00:35:00.514Z","contentChangedAt":"2026-09-16T00:35:00.514Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}