tui-cs/Terminal.Gui · error · NotSupportedException
Cloning of collection type {type.Name} is not supported with
Error message
Cloning of collection type {type.Name} is not supported without a parameterless constructor. What it means
Thrown by DeepCloner.CloneCollection when an ICollection-implementing, IList-implementing collection type cannot be instantiated as an IList via Activator.CreateInstance(type). The cloner refuses to clone collections it cannot construct with a parameterless constructor, because it needs an empty destination list to copy cloned elements into. This is a hard guard at DeepCloner.cs:228-231.
Source
Thrown at Terminal.Gui/Configuration/DeepCloner.cs:230
// Check for immutable collections and throw if found
if (type.IsGenericType)
{
Type genericTypeDef = type.GetGenericTypeDefinition ();
if (genericTypeDef.FullName != null && genericTypeDef.FullName.StartsWith ("System.Collections.Immutable"))
{
throw new NotSupportedException ($"Cloning of immutable collections like {type.Name} is not supported.");
}
}
if (source is not IList)
{
throw new NotSupportedException ($"Cloning of collection type {type.Name} is not supported unless it implements IList.");
}
if (Activator.CreateInstance (type) is not IList tempList)
{
throw new NotSupportedException ($"Cloning of collection type {type.Name} is not supported without a parameterless constructor.");
}
// Add to visited before cloning contents to prevent circular reference issues
visited.TryAdd (source, tempList);
foreach (object? item in (IEnumerable)source)
{
object? clonedItem = DeepCloneInternal (item, visited);
tempList.Add (clonedItem);
}
return tempList;
}
#region Dictionary Support
[UnconditionalSuppressMessage ("AOT", "IL3050", Justification = "Dictionary cloning constructs supported runtime dictionary shapes (Dictionary<,> and ConcurrentDictionary<,>) via MakeGenericType, which is validated by NativeAOT publish tests.")]
[UnconditionalSuppressMessage ("Trimming", "IL2075", Justification = "Dictionary cloning reads the runtime dictionary comparer from supported dictionary types to preserve comparer semantics.")]View on GitHub (pinned to 2e47b11478)
Solutions
- Replace the custom collection type with List<T> (which has a parameterless constructor) for any property that participates in a configuration scope.
- Add a public parameterless constructor to the custom collection type so Activator.CreateInstance can build it.
- Ensure the collection type implements IList (not just ICollection/IEnumerable); types implementing only ICollection and IEnumerable but not IList hit the earlier guard at line 223-226, not this one.
- If running under NativeAOT, register the collection type in a JsonSerializerContext (SourceGenerationContext) so the AOT fallback path in CreateInstance/DeepCloneInternal can construct it.
- Avoid storing immutable or frozen collections in clonable config; convert to List<T> before assigning to a ConfigProperty.
Example fix
// before
public class MyScope
{
public ReadOnlyCollection<int> Items { get; set; } // no parameterless ctor, not IList-creatable
}
// after
public class MyScope
{
public List<int> Items { get; set; } = new ();
} Defensive patterns
Strategy: type-guard
Validate before calling
// Before cloning, verify the collection type is IList-constructible
static bool IsClonableCollection (object? obj)
{
if (obj is not IList) return false;
Type t = obj.GetType ();
return t.GetConstructor (Type.EmptyTypes) != null
&& typeof (IList).IsAssignableFrom (t);
}
// Usage
if (!IsClonableCollection (myConfigProperty))
{
myConfigProperty = new List<...> (...); // normalize to List<T>
} Type guard
static bool IsClonableCollection<T> (T value) where T : notnull
{
Type t = value.GetType ();
return value is IList
&& t.GetConstructor (Type.EmptyTypes) is not null
&& !t.FullName!.StartsWith ("System.Collections.Immutable");
} Try / catch
try
{
var clone = DeepCloner.DeepClone (configObject);
}
catch (NotSupportedException ex) when (ex.Message.Contains ("parameterless constructor"))
{
// Normalize the offending collection to List<T> and retry,
// or report which property holds the unsupported type.
} Prevention
- Use List<T> for all collection-typed configuration properties.
- Never store immutable/frozen collections in objects passed to DeepClone.
- Add a unit test that DeepClones every configuration scope type to catch unsupported types early.
- Under NativeAOT, register collection types in a JsonSerializerContext so the AOT fallback can construct them.
When it happens
Trigger: DeepClone is called on an object graph that transitively contains an ICollection whose runtime type (1) has no public parameterless constructor, or (2) returns a non-IList instance from Activator.CreateInstance (e.g. a Nullable<T>-boxed struct, or a collection whose default ctor yields a type not assignable to IList). In practice this most often surfaces under NativeAOT/trimming where Activator.CreateInstance returns null for trimmed constructors before this line, or for custom collection types with only parameterized constructors.
Common situations: A user stores a custom collection type (with only an int-capacity or IEqualityComparer constructor) inside a configuration scope property; ConfigurationManager applies the scope and triggers a deep clone. Also seen after upgrading to a Terminal.Gui version that deep-clones more aggressively, exposing a previously-uncloned custom collection.
Related errors
- Cannot create instance of type {type.FullName}. No parameter
- Cannot create instance of type {type.FullName} in AOT contex
- Cloning of collection type {type.Name} is not supported unle
- Unsupported dictionary type: {type}. Only Dictionary<,> and
- Error Applying Configuration Change: {tie.InnerException.Mes
AI-assisted analysis of tui-cs/Terminal.Gui@2e47b11478 (2026-08-13).
Data as JSON: /api/errors/ec26c6b624c47f16.
Report an issue: GitHub.