tui-cs/Terminal.Gui · error · JsonException

Duplicate key '{key}' in dictionary.

Error message

Duplicate key '{key}' in dictionary.

What it means

Thrown by ConcurrentDictionaryJsonConverter<T>.Read when dictionary.TryAdd(key, value) returns false, meaning two entries in the JSON array used the same key string. The comparer is invariant-culture (case-insensitive only if options.PropertyNameCaseInsensitive), so "Default" and "default" may collide depending on options.

Source

Thrown at Terminal.Gui/Configuration/ConcurrentDictionaryJsonConverter.cs:41

                                                          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 ();
                    object value = JsonSerializer.Deserialize (ref reader, typeof (T), TuiSerializerContext.Instance);

                    if (!dictionary.TryAdd (key, (T)value))
                    {
                        throw new JsonException ($"Duplicate key '{key}' in dictionary.");
                    }
                }
            }
            else if (reader.TokenType == JsonTokenType.EndArray)
            {
                break;
            }
        }

        return dictionary;
    }

    public override void Write (Utf8JsonWriter writer, ConcurrentDictionary<string, T> value, JsonSerializerOptions options)
    {
        writer.WriteStartArray ();

        foreach (KeyValuePair<string, T> item in value)
        {

View on GitHub (pinned to 2e47b11478)

Solutions

  1. Search the config for the duplicated key (case-insensitively) and remove or rename the extra entry.
  2. If you intended to override, keep only one definition per key.
  3. Check PropertyNameCaseInsensitive setting on your JsonSerializerOptions to know whether case variants count as duplicates.

Example fix

// before
"Themes": [ {"Default": {...}}, {"Default": {...}} ]
// after
"Themes": [ {"Default": {...}}, {"Dark": {...}} ]
Defensive patterns

Strategy: validation

Validate before calling

// Detect duplicate theme keys before Load.
using var doc = JsonDocument.Parse (jsonString);
var seen = new HashSet<string> (StringComparer.OrdinalIgnoreCase);
foreach (var obj in doc.RootElement.GetProperty ("Themes").EnumerateArray ())
{
    foreach (var p in obj.EnumerateObject ())
        if (!seen.Add (p.Name))
            throw new FormatException ($"Duplicate theme key: {p.Name}");
}

Try / catch

try { ConfigurationManager.Load (locations); }
catch (JsonException ex) when (ex.Message.Contains ("Duplicate key"))
{ /* remove the duplicate entry */ }

Prevention

When it happens

Trigger: A Themes array contains two objects with the same key: [ {"Default": {...}}, {"Default": {...}} ].

Common situations: Merging two config files that both define the same theme; case-variant duplicates when case-insensitive matching is on; copy-paste of a theme block without renaming.

Related errors


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