{"record":{"id":"166238bb65f96415","repo":"microsoft/aspire","slug":"expected-propertyname-got-reader-tokentype","errorCode":null,"errorMessage":"Expected PropertyName, got {reader.TokenType}","messagePattern":"Expected PropertyName, got (.+?)","errorType":"exception","errorClass":"JsonException","httpStatus":null,"severity":"error","filePath":"src/Aspire.Cli/Configuration/FlexibleBooleanDictionaryConverter.cs","lineNumber":39,"sourceCode":"        }\n\n        if (reader.TokenType != JsonTokenType.StartObject)\n        {\n            throw new JsonException($\"Expected StartObject, got {reader.TokenType}\");\n        }\n\n        var dictionary = new Dictionary<string, bool>();\n\n        while (reader.Read())\n        {\n            if (reader.TokenType == JsonTokenType.EndObject)\n            {\n                return dictionary;\n            }\n\n            if (reader.TokenType != JsonTokenType.PropertyName)\n            {\n                throw new JsonException($\"Expected PropertyName, got {reader.TokenType}\");\n            }\n\n            var key = reader.GetString() ?? throw new JsonException(\"Property name cannot be null\");\n\n            reader.Read();\n\n            bool value = reader.TokenType switch\n            {\n                JsonTokenType.True => true,\n                JsonTokenType.False => false,\n                JsonTokenType.String => ParseBooleanString(reader.GetString(), key),\n                _ => throw new JsonException($\"Cannot convert {reader.TokenType} to boolean for key '{key}'\")\n            };\n\n            dictionary[key] = value;\n        }\n\n        throw new JsonException(\"Unexpected end of JSON\");","sourceCodeStart":21,"sourceCodeEnd":57,"githubUrl":"https://github.com/microsoft/aspire/blob/25830f84bd145686607ad00c057b3f84e2e51d43/src/Aspire.Cli/Configuration/FlexibleBooleanDictionaryConverter.cs#L21-L57","documentation":"While iterating the members of a dictionary-shaped JSON object, the converter expects each token after StartObject (or after a value) to be a PropertyName; any other token throws JsonException. This indicates malformed or structurally unexpected JSON rather than a value-level problem.","triggerScenarios":"Malformed JSON where an array or scalar appears where a property name should be; JSON that closes the object then contains trailing tokens reaching the converter loop; programmatically constructed reader sequences.","commonSituations":"Hand-crafted or machine-generated JSON with structural mistakes; interleaved edits corrupting a config file; a serializer upstream writing an unexpected shape for this section.","solutions":["Validate the JSON file with a JSON linter/parser to find the structural error near the reported property.","Repair the object so every entry is \"name\": value pairs inside the braces.","If generated, fix the generator to emit a plain JSON object for this property."],"exampleFix":"// before (array where object properties expected)\n\"featureFlags\": [\"A\", \"B\"]\n// after\n\"featureFlags\": { \"A\": true, \"B\": false }","handlingStrategy":"try-catch","validationCode":"try { using var _ = JsonDocument.Parse(json); } // full structural validation first\ncatch (JsonException ex) { throw new FormatException($\"Malformed JSON: {ex.Message}\"); }","typeGuard":null,"tryCatchPattern":"try\n{\n    var config = JsonSerializer.Deserialize<MyConfig>(json, options);\n}\ncatch (JsonException ex) when (ex.Message.StartsWith(\"Expected PropertyName\"))\n{\n    logger.LogError(ex, \"Malformed JSON object structure in configuration.\");\n}","preventionTips":["Run JSON through a linter/parser after every manual edit.","Avoid hand-editing generated config sections.","Keep config files under source control so corruption is diffable."],"tags":["json","malformed-json","deserialization"],"backgroundTag":"json-parse-error","analyzedSha":"25830f84bd145686607ad00c057b3f84e2e51d43","analyzedAt":"2026-09-16T11:10:06.193Z","contentChangedAt":"2026-09-16T11:10:06.193Z","schemaVersion":2},"datasetVersion":"2026-09-21T09:17:21.228Z"}