{"record":{"id":"655cc0d4ec79335a","repo":"tui-cs/Terminal.Gui","slug":"unsupported-dictionary-type-type-only-dictiona","errorCode":null,"errorMessage":"Unsupported dictionary type: {type}. Only Dictionary<,> and ConcurrentDictionary<,> are supported.","messagePattern":"Unsupported dictionary type: (.+?)\\. Only Dictionary<,> and ConcurrentDictionary<,> are supported\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"Terminal.Gui/Configuration/DeepCloner.cs","lineNumber":309,"sourceCode":"            CheckForUnsupportedDictionaryTypes (type);\n        }\n\n        Type [] genericArgs = type.GetGenericArguments ();\n        Type dictType;\n\n        if (genericArgs.Length == 2)\n        {\n            if (type.GetGenericTypeDefinition () == typeof (Dictionary<,>))\n            {\n                dictType = typeof (Dictionary<,>).MakeGenericType (genericArgs);\n            }\n            else if (type.GetGenericTypeDefinition () == typeof (ConcurrentDictionary<,>))\n            {\n                dictType = typeof (ConcurrentDictionary<,>).MakeGenericType (genericArgs);\n            }\n            else\n            {\n                throw new InvalidOperationException (\n                                                     $\"Unsupported dictionary type: {type}. Only Dictionary<,> and ConcurrentDictionary<,> are supported.\");\n            }\n        }\n        else\n        {\n            dictType = typeof (Dictionary<object, object>);\n        }\n\n        object? comparer = type.GetProperty (\"Comparer\")?.GetValue (source);\n\n        IDictionary tempDict = CreateDictionaryInstance (dictType, comparer);\n        visited.TryAdd (source, tempDict);\n\n        object? lastKey = null;\n\n        try\n        {\n            // Clone all key-value pairs","sourceCodeStart":291,"sourceCodeEnd":327,"githubUrl":"https://github.com/tui-cs/Terminal.Gui/blob/2e47b11478db083499917f2ad27c34d30efb0df1/Terminal.Gui/Configuration/DeepCloner.cs#L291-L327","documentation":"Thrown by DeepCloner.CloneDictionary when the source is an IDictionary whose closed generic type is neither System.Collections.Generic.Dictionary<,> nor System.Collections.Concurrent.ConcurrentDictionary<,>. The cloner only knows how to reconstruct those two concrete dictionary shapes (DeepCloner.cs:297-312); any other two-argument generic dictionary (SortedDictionary, ReadOnlyDictionary, custom IDictionary<,>) is rejected with InvalidOperationException.","triggerScenarios":"A configuration property holds a SortedDictionary<TKey,TValue>, ReadOnlyDictionary<TKey,TValue>, OrderedDictionary, a custom class implementing IDictionary<,>, or any third-party dictionary type. DeepClone is invoked on the owning scope/config object, reaches CloneDictionary, finds genericArgs.Length==2, but type.GetGenericTypeDefinition() matches neither supported type.","commonSituations":"User switches a config property from Dictionary to SortedDictionary for deterministic key ordering. User wraps a dictionary in ReadOnlyDictionary<,> for immutability. A third-party theme/config extension introduces a custom IDictionary<,> subclass stored in a ThemeScope.","solutions":["Use Dictionary<TKey,TValue> or ConcurrentDictionary<TKey,TValue> for any dictionary that will be deep-cloned by the configuration system.","If ordering is needed, sort keys when reading rather than using SortedDictionary<,>.","If read-only semantics are needed, keep the storage as Dictionary<,> and expose a read-only view wrapper that is NOT the cloned property type.","For custom IDictionary<,> subclasses, either inherit from Dictionary<,>/ConcurrentDictionary<,> directly (so GetGenericTypeDefinition still matches) or move the custom type out of the clonable property graph.","If the dictionary is nested in a ConfigProperty, set ConfigProperty.Immutable or restructure so it is not deep-cloned."],"exampleFix":"// before\npublic SortedDictionary<string, Scheme> Schemes { get; set; }\n\n// after\npublic Dictionary<string, Scheme> Schemes { get; set; } = new ();","handlingStrategy":"type-guard","validationCode":"static bool IsSupportedDictionary (object? obj)\n{\n    if (obj is not IDictionary) return false;\n    Type t = obj.GetType ();\n    if (!t.IsGenericType) return true; // non-generic path uses Dictionary<object,object>\n    Type gtd = t.GetGenericTypeDefinition ();\n    return gtd == typeof (Dictionary<,>) || gtd == typeof (ConcurrentDictionary<,>);\n}\n\nif (!IsSupportedDictionary (myDict))\n{\n    myDict = new Dictionary<...> (myDict); // normalize\n}","typeGuard":"static bool IsSupportedDictionary<T> (T value) where T : notnull\n{\n    Type t = value.GetType ();\n    if (!t.IsGenericType) return value is IDictionary;\n    Type gtd = t.GetGenericTypeDefinition ();\n    return gtd == typeof (Dictionary<,>) || gtd == typeof (ConcurrentDictionary<,>);\n}","tryCatchPattern":"try\n{\n    var clone = DeepCloner.DeepClone (configWithDict);\n}\ncatch (InvalidOperationException ex) when (ex.Message.Contains (\"Unsupported dictionary type\"))\n{\n    // Convert the offending dictionary to Dictionary<,> and retry.\n}","preventionTips":["Standardize on Dictionary<,> or ConcurrentDictionary<,> for all configuration dictionaries.","Avoid SortedDictionary, ReadOnlyDictionary, and custom IDictionary subclasses in clonable graphs.","If a custom dictionary subclass is needed, inherit from Dictionary<,>/ConcurrentDictionary<,> directly.","Add a clone-roundtrip test for every config scope type."],"tags":["deepcloner","dictionaries","configuration","reflection"],"backgroundTag":null,"analyzedSha":"2e47b11478db083499917f2ad27c34d30efb0df1","analyzedAt":"2026-08-13T19:20:08.826Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}