microsoft/aspire · error · JsonException

Expected StartObject, got

Error message

Expected StartObject, got {reader.TokenType}

What it means

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.

Solutions

  1. Fix the JSON so the property is an object with boolean (or 'true'/'false' string) values.
  2. Check the schema the CLI expects for this configuration section and restructure the value accordingly.
  3. If null should be tolerated, note the converter already returns null for Null token; only other non-object tokens throw.

Example fix

// before
"featureFlags": "enabled"
// after
"featureFlags": { "MyFeature": "true" }
Defensive patterns

Strategy: validation

Validate before calling

using var doc = JsonDocument.Parse(json);
if (doc.RootElement.TryGetProperty("featureFlags", out var flags) && flags.ValueKind != JsonValueKind.Object && flags.ValueKind != JsonValueKind.Null)
    throw new FormatException("featureFlags must be a JSON object.");

Try / catch

try
{
    var config = JsonSerializer.Deserialize<MyConfig>(json, options);
}
catch (JsonException ex) when (ex.Message.StartsWith("Expected StartObject"))
{
    logger.LogError(ex, "Config section expected to be an object but was another JSON kind.");
}

Prevention

When it happens

Trigger: 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".

Common situations: 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.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


AI-assisted analysis of microsoft/aspire@25830f84bd (2026-09-16). Data as JSON: /api/errors/930069a9fe310805. Report an issue: GitHub.

Appendix: source

Thrown at src/Aspire.Cli/Configuration/FlexibleBooleanDictionaryConverter.cs:25

namespace Aspire.Cli.Configuration;

/// <summary>
/// A JSON converter that handles Dictionary&lt;string, bool&gt; with flexible boolean parsing.
/// Accepts both actual boolean values (true/false) and string representations ("true"/"false").
/// This provides backward compatibility for settings files that may have string values.
/// </summary>
internal sealed class FlexibleBooleanDictionaryConverter : JsonConverter<Dictionary<string, bool>>
{
    public override Dictionary<string, bool>? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        if (reader.TokenType == JsonTokenType.Null)
        {
            return null;
        }

        if (reader.TokenType != JsonTokenType.StartObject)
        {
            throw new JsonException($"Expected StartObject, got {reader.TokenType}");
        }

        var dictionary = new Dictionary<string, bool>();

        while (reader.Read())
        {
            if (reader.TokenType == JsonTokenType.EndObject)
            {
                return dictionary;
            }

            if (reader.TokenType != JsonTokenType.PropertyName)
            {
                throw new JsonException($"Expected PropertyName, got {reader.TokenType}");
            }

            var key = reader.GetString() ?? throw new JsonException("Property name cannot be null");

View on GitHub (pinned to 25830f84bd)