tui-cs/Terminal.Gui · error · JsonException
Expected a JSON array ("[ {{ ... }} ]"), but got "{reader.To
Error message
Expected a JSON array ("[ {{ ... }} ]"), but got "{reader.TokenType}". What it means
Thrown by ConcurrentDictionaryJsonConverter<T>.Read: Terminal.Gui serializes its ConcurrentDictionary<string,T> properties (e.g. Themes) as a JSON ARRAY of single-key objects ([ {"key": value}, ... ]), not as a JSON object. If the reader's first token is not StartArray, this fires.
Source
Thrown at Terminal.Gui/Configuration/ConcurrentDictionaryJsonConverter.cs:18
#nullable disable
using System.Collections.Concurrent;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace Terminal.Gui.Configuration;
internal class ConcurrentDictionaryJsonConverter<T> : JsonConverter<ConcurrentDictionary<string, T>>
{
public override ConcurrentDictionary<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
ConcurrentDictionary<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
- Wrap each key/value pair as its own object inside an array: [ {"ThemeName": { ...scheme... } } ].
- Export a config from ConfigurationManager once to see the exact array shape it expects, then mirror it.
- Use a JSON schema for the config to enforce the array shape.
Example fix
// before
"Themes": { "Default": { ... } }
// after
"Themes": [ { "Default": { ... } } ] Defensive patterns
Strategy: validation
Validate before calling
// Themes must be a JSON array of single-key objects.
using var doc = JsonDocument.Parse (jsonString);
if (doc.RootElement.GetProperty ("Themes").ValueKind != JsonValueKind.Array)
throw new FormatException ("Themes must be a JSON array [ {key: value}, ... ]."); Type guard
static bool ThemesIsArrayShape (JsonElement themes) =>
themes.ValueKind == JsonValueKind.Array
&& themes.EnumerateArray ().All (e => e.ValueKind == JsonValueKind.Object && e.EnumerateObject ().Count () == 1); Try / catch
try { ConfigurationManager.Load (locations); }
catch (JsonException ex) when (ex.Message.Contains ("Expected a JSON array"))
{ /* rewrap the object-form Themes into an array */ } Prevention
- Serialize a sample config once to capture the array shape for Themes.
- Add a JSON schema that types Themes as array-of-single-key-objects.
When it happens
Trigger: A config file provides Themes as a JSON object { "Default": {...} } instead of an array [ {"Default": {...}} ]. Also fires on a bare scalar or string where the array is expected.
Common situations: Author assumes the natural JSON object shape for a map; migrating from a system that uses object-form maps; hand-editing a Themes section.
Related errors
- Duplicate key '{key}' in dictionary.
- {propertyName}: Unexpected token when parsing Attribute: {re
- {propertyName}: Expected a string value.
- Expected a valid text style value.
- {propertyName}: Unknown Attribute property .
AI-assisted analysis of tui-cs/Terminal.Gui@2e47b11478 (2026-08-13).
Data as JSON: /api/errors/7f4133fc13e6f832.
Report an issue: GitHub.