{"record":{"id":"26de5691e7a9575f","repo":"tui-cs/Terminal.Gui","slug":"propertyname-json-error-in-scopejsonconverter","errorCode":null,"errorMessage":"{propertyName}: Json error in ScopeJsonConverter","messagePattern":"(.+?): Json error in ScopeJsonConverter","errorType":"exception","errorClass":"JsonException","httpStatus":null,"severity":"error","filePath":"Terminal.Gui/Configuration/ScopeJsonConverter.cs","lineNumber":146,"sourceCode":"                                                                 })\n                                                         .FirstOrDefault ();\n\n                if (property is { })\n                {\n                    // Set the value of propertyName on the scopeT.\n                    PropertyInfo prop = typeof (TScopeT).GetProperty (propertyName!)!;\n\n                    prop.SetValue (scope, JsonSerializer.Deserialize (ref reader, prop.PropertyType, TuiSerializerContext.Instance));\n                }\n                else\n                {\n                    // Unknown property\n                    throw new JsonException ($\"{propertyName}: Unknown property name.\");\n                }\n            }\n        }\n\n        throw new JsonException ($\"{propertyName}: Json error in ScopeJsonConverter\");\n    }\n\n    [UnconditionalSuppressMessage (\"AOT\",\n                                   \"IL3050:Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling.\",\n                                   Justification =\n                                       \"Arbitrary property-level converter fallback is guarded by RuntimeFeature.IsDynamicCodeSupported and is unreachable under NativeAOT.\")]\n    [UnconditionalSuppressMessage (\"Trimming\",\n                                   \"IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code\",\n                                   Justification =\n                                       \"Arbitrary property-level converter fallback is only used when a consumer opts into a custom property-level JsonConverter on JIT-supported runtimes.\")]\n    public override void Write (Utf8JsonWriter writer, TScopeT scope, JsonSerializerOptions options)\n    {\n        writer.WriteStartObject ();\n\n        IEnumerable<PropertyInfo> properties = typeof (TScopeT).GetProperties ().Where (p => p.GetCustomAttribute (typeof (JsonIncludeAttribute)) != null);\n\n        foreach (PropertyInfo p in properties)\n        {","sourceCodeStart":128,"sourceCodeEnd":164,"githubUrl":"https://github.com/tui-cs/Terminal.Gui/blob/2e47b11478db083499917f2ad27c34d30efb0df1/Terminal.Gui/Configuration/ScopeJsonConverter.cs#L128-L164","documentation":"Terminal-final fallback thrown at the end of ScopeJsonConverter.Read when the Utf8JsonReader loop exits without returning a parsed scope object. In practice this means the JSON document for a configuration scope (SettingsScope/ThemeScope/AppSettingsScope) was truncated or malformed so the reader never produced the matching EndObject token before the stream ended. The message is intentionally generic because the parser could not associate the failure with a specific property.","triggerScenarios":"Deserializing a config JSON stream (via SourcesManager.Load -> JsonSerializer.Deserialize with TuiSerializerContext.Instance.SettingsScope) where the byte stream ends mid-object — e.g. a config.json file cut off after \"\\\"Theme\\\": \\\"Default\\\"\" with no closing brace, or a network/resource stream that returned EOF early. Also reachable if reader.Read() returns false because the stream is empty after the StartObject token.","commonSituations":"A user hand-edits .tui/config.json or <App>.config.json and forgets the closing brace; an editor or sync tool truncated the file; an embedded resource was generated incorrectly; the TUI_CONFIG environment variable points at a partial file.","solutions":["Validate the offending config file with a JSON linter (e.g. 'dotnet run --project ...' won't help; use 'jq . config.json' or a VS Code JSON validator) and add the missing closing brace.","Identify which source is broken: check ConfigurationManager.Sources (the ConcurrentDictionary<ConfigLocations,string>) for the file paths/resources that were probed, then validate each one.","Enable ConfigurationManager.ThrowOnJsonErrors = true early in startup so the exact source and message surface as a real exception with a path, instead of being swallowed and printed at shutdown.","If the stream comes from your own code, ensure you flush and reset Position before passing it to SourcesManager.Load(Stream,...)."],"exampleFix":"// before: config.json on disk\n{\n  \"Theme\": \"Default\"\n// after\n{\n  \"Theme\": \"Default\"\n}","handlingStrategy":"validation","validationCode":"// Validate a config file is well-formed JSON with an object root before Terminal.Gui loads it\nbool IsValidConfigRoot (string path)\n{\n    try\n    {\n        using JsonDocument doc = JsonDocument.Parse (File.ReadAllText (path));\n        return doc.RootElement.ValueKind == JsonValueKind.Object;\n    }\n    catch { return false; }\n}","typeGuard":null,"tryCatchPattern":"// Keep ThrowOnJsonErrors false (default) so a broken file is logged, not fatal; or wrap explicitly\nConfigurationManager.ThrowOnJsonErrors = false; // default\ntry { /* trigger config load */ }\ncatch (JsonException ex) { /* only if you set ThrowOnJsonErrors=true */ Logging.Error (ex.Message); }","preventionTips":["Keep ConfigurationManager.ThrowOnJsonErrors = false (the default) in production so one bad file does not crash startup.","Run a JSON validator over .tui/config.json and <App>.config.json in CI.","Write config files atomically (temp file + rename) to avoid truncated files from partial writes."],"tags":["config","json","serialization","scope-json-converter"],"backgroundTag":null,"analyzedSha":"2e47b11478db083499917f2ad27c34d30efb0df1","analyzedAt":"2026-08-13T19:20:08.826Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}