tui-cs/Terminal.Gui · error · JsonException

Expected a JSON array ("[ { ... } ]"), but got "{reader.Toke

Error message

Expected a JSON array ("[ { ... } ]"), but got "{reader.TokenType}".

What it means

Thrown by DictionaryJsonConverter<T>.Read (DictionaryJsonConverter.cs:15-18) when the JSON token is not StartArray. Terminal.Gui serializes Dictionary<string,T> config values as a JSON ARRAY of single-key objects (e.g. [{"key": value}, ...]), not as a JSON object. Feeding a conventional JSON object {"key": value} for such a property triggers this JsonException.

Source

Thrown at Terminal.Gui/Configuration/DictionaryJsonConverter.cs:17

#nullable disable
using System.Text.Json;
using System.Text.Json.Serialization;

namespace Terminal.Gui.Configuration;

internal class DictionaryJsonConverter<T> : JsonConverter<Dictionary<string, T>>
{
    public override Dictionary<string, T> Read (
        ref Utf8JsonReader reader,
        Type typeToConvert,
        JsonSerializerOptions options
    )
    {
        if (reader.TokenType != JsonTokenType.StartArray)
        {
            throw new JsonException ($"Expected a JSON array (\"[ {{ ... }} ]\"), but got \"{reader.TokenType}\".");
        }

        // If the Json options indicate ignoring case, use the invariant culture ignore case comparer.
        Dictionary<string, T> dictionary = new (
                                                options.PropertyNameCaseInsensitive
                                                    ? StringComparer.InvariantCultureIgnoreCase
                                                    : StringComparer.InvariantCulture);

        while (reader.Read ())
        {
            if (reader.TokenType == JsonTokenType.StartObject)
            {
                reader.Read ();

                if (reader.TokenType == JsonTokenType.PropertyName)
                {
                    string key = reader.GetString ();
                    reader.Read ();

View on GitHub (pinned to 2e47b11478)

Solutions

  1. Rewrite the dictionary property as a JSON array of single-property objects: [{"Key1": val1}, {"Key2": val2}].
  2. Validate the config file shape against a Terminal.Gui config schema before loading.
  3. Use ConfigurationManager to serialize a sample config once and use that output as the canonical format template.
  4. If you control the producer, ensure it emits arrays for Dictionary<string,T> properties.

Example fix

// before (wrong — object form)
"Schemes": {
  "Base": { "Normal": { "Foreground": "White" } }
}

// after (correct — array of singletons)
"Schemes": [
  { "Base": { "Normal": { "Foreground": "White" } } }
]
Defensive patterns

Strategy: validation

Validate before calling

// Validate that a Dictionary<string,T> property is a JSON array before deserializing
using System.Text.Json;

static bool IsDictionaryPropertyArrayForm (string json, string propertyName)
{
    using JsonDocument doc = JsonDocument.Parse (json);
    if (!doc.RootElement.TryGetProperty (propertyName, out JsonElement el)) return true; // absent is fine
    return el.ValueKind == JsonValueKind.Array;
}

if (!IsDictionaryPropertyArrayForm (configJson, "Schemes"))
{
    // rewrite the property to array-of-singletons form before loading
}

Type guard

static bool IsArrayForm (JsonElement el) => el.ValueKind == JsonValueKind.Array;

Try / catch

try
{
    ConfigurationManager.Load (configJson);
}
catch (JsonException ex) when (ex.Message.Contains ("Expected a JSON array"))
{
    // The dictionary property was given as an object; convert it to
    // [{"key": value}, ...] array form and reload.
}

Prevention

When it happens

Trigger: A config JSON file (themes, app settings) has a dictionary-typed property written as a JSON object instead of the array-of-singletons form the converter expects. Also triggered by hand-editing config to the 'natural' object form, or by importing JSON produced by a different serializer that emits objects.

Common situations: User manually authors a theme JSON and writes "Schemes": { "Base": {...} } instead of "Schemes": [ { "Base": {...} } ]. A config migration tool emits standard object dictionaries. Copy-pasting a JSON snippet from docs that used the object form.

Related errors


AI-assisted analysis of tui-cs/Terminal.Gui@2e47b11478 (2026-08-13). Data as JSON: /api/errors/3107b06b476d5fd6. Report an issue: GitHub.