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
- Search the config for the duplicated key (case-insensitively) and remove or rename the extra entry.
- If you intended to override, keep only one definition per key.
- 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
- Dedupe theme keys when merging config files.
- Be aware of the invariant-culture (and optional case-insensitive) comparer.
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
- Expected a JSON array ("[ {{ ... }} ]"), but got "{reader.To
- {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/696a4cce414e2b7d.
Report an issue: GitHub.