{"record":{"id":"930069a9fe310805","repo":"microsoft/aspire","slug":"expected-startobject-got-reader-tokentype","errorCode":null,"errorMessage":"Expected StartObject, got {reader.TokenType}","messagePattern":"Expected StartObject, got (.+?)","errorType":"exception","errorClass":"JsonException","httpStatus":null,"severity":"error","filePath":"src/Aspire.Cli/Configuration/FlexibleBooleanDictionaryConverter.cs","lineNumber":25,"sourceCode":"namespace Aspire.Cli.Configuration;\n\n/// <summary>\n/// A JSON converter that handles Dictionary&lt;string, bool&gt; with flexible boolean parsing.\n/// Accepts both actual boolean values (true/false) and string representations (\"true\"/\"false\").\n/// This provides backward compatibility for settings files that may have string values.\n/// </summary>\ninternal sealed class FlexibleBooleanDictionaryConverter : JsonConverter<Dictionary<string, bool>>\n{\n    public override Dictionary<string, bool>? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)\n    {\n        if (reader.TokenType == JsonTokenType.Null)\n        {\n            return null;\n        }\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","sourceCodeStart":7,"sourceCodeEnd":43,"githubUrl":"https://github.com/microsoft/aspire/blob/25830f84bd145686607ad00c057b3f84e2e51d43/src/Aspire.Cli/Configuration/FlexibleBooleanDictionaryConverter.cs#L7-L43","documentation":"FlexibleBooleanDictionaryConverter.Read expects the value of a dictionary-shaped config property to be a JSON object; when the token is anything else it throws JsonException naming the actual token type. This guards the Dictionary<string,bool> deserialization path.","triggerScenarios":"Feeding System.Text.Json a JSON document where a property mapped to Dictionary<string,bool> is a string, array, number, or null token instead of an object, e.g. \"featureFlags\": \"enabled\".","commonSituations":"Config schema drift — user writes a flat value where a nested map is required; migrating from a different config format; copy/paste errors in JSON.","solutions":["Fix the JSON so the property is an object with boolean (or 'true'/'false' string) values.","Check the schema the CLI expects for this configuration section and restructure the value accordingly.","If null should be tolerated, note the converter already returns null for Null token; only other non-object tokens throw."],"exampleFix":"// before\n\"featureFlags\": \"enabled\"\n// after\n\"featureFlags\": { \"MyFeature\": \"true\" }","handlingStrategy":"validation","validationCode":"using var doc = JsonDocument.Parse(json);\nif (doc.RootElement.TryGetProperty(\"featureFlags\", out var flags) && flags.ValueKind != JsonValueKind.Object && flags.ValueKind != JsonValueKind.Null)\n    throw new FormatException(\"featureFlags must be a JSON object.\");","typeGuard":null,"tryCatchPattern":"try\n{\n    var config = JsonSerializer.Deserialize<MyConfig>(json, options);\n}\ncatch (JsonException ex) when (ex.Message.StartsWith(\"Expected StartObject\"))\n{\n    logger.LogError(ex, \"Config section expected to be an object but was another JSON kind.\");\n}","preventionTips":["Keep dictionary-shaped config values as JSON objects, never scalars or arrays.","Validate config JSON structure before deserialization.","Update config files when migrating between schema versions."],"tags":["json","configuration","deserialization"],"backgroundTag":"schema-validation-failed","analyzedSha":"25830f84bd145686607ad00c057b3f84e2e51d43","analyzedAt":"2026-09-16T11:10:06.193Z","contentChangedAt":"2026-09-16T11:10:06.193Z","schemaVersion":2},"datasetVersion":"2026-09-21T04:17:39.646Z"}