stride3d/stride · error · ArgumentException
Type [ ] is not supported as a modifiable collection
Error message
Type [{type}] is not supported as a modifiable collection What it means
OldCollectionDescriptor's constructor inspects the type for supported collection interfaces (IList/ICollection/arrays with indexers, etc.). If the type implements none of the supported modifiable collection shapes, it throws ArgumentException 'Type [{type}] is not supported as a modifiable collection'. The descriptor needs known Add/Remove/Insert/indexer methods to support editing.
Solutions
- Make the type implement IList or ICollection<T> (e.g. inherit from List<T> or Collection<T>).
- Use a supported collection type (List<T>, T[], ObservableCollection<T>, HashSet<T>) instead of a custom one.
- Register the type with the correct descriptor (ObjectDescriptor or SetDescriptor) if it is not a collection.
Example fix
// before
public class MyItems { /* no collection interface */ }
// after
public class MyItems : List<Item> { } Defensive patterns
Strategy: validation
Validate before calling
bool supported = type.IsArray
|| typeof(IList).IsAssignableFrom(type)
|| (type.IsGenericType && typeof(ICollection<>).IsAssignableFrom(type.GetGenericTypeDefinition().MakeGenericType(type.GetGenericArguments())));
if (!supported) throw new InvalidOperationException($"{type} is not a supported modifiable collection"); Type guard
static bool IsModifiableCollection(Type t) => t.IsArray || typeof(IList).IsAssignableFrom(t) || t.GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(ICollection<>));
Try / catch
try { var d = new OldCollectionDescriptor(factory, type, emit, conv); }
catch (ArgumentException ex) when (ex.Message.Contains("not supported as a modifiable collection")) { /* fall back to ObjectDescriptor */ } Prevention
- Base serializable collections on List<T>, Collection<T>, arrays, or ObservableCollection<T>.
- Ensure custom collections implement IList or ICollection<T>.
- Avoid serializing IEnumerable-only results (LINQ queries, iterators).
When it happens
Trigger: Constructing OldCollectionDescriptor for a type that is not a recognized modifiable collection — e.g. IEnumerable-only types, custom collections implementing neither IList nor ICollection<T>, dictionaries routed to the wrong descriptor.
Common situations: Trying to serialize/edit read-only sequences (yield-return iterators, LINQ query results); custom collection classes missing standard interfaces; types registered with the wrong descriptor factory branch.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- Expecting a type inheriting from System.Collections.ISet
- The type of collection does not have a parameterless…
- The type of dictionary does not have a parameterless…
- Invalid assembly path. Doesn't contain directory information
- The property [ ] of type [ ] has no setter.
AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14).
Data as JSON: /api/errors/a6e9f06551671633.
Report an issue: GitHub.
Appendix: source
Thrown at sources/core/Stride.Core.Reflection/TypeDescriptors/OldCollectionDescriptor.cs:115
var removeAt = type.GetMethod(nameof(IList<object>.RemoveAt), [typeof(int)]);
if (removeAt != null)
removeAtMethod = (obj, index) => removeAt.Invoke(obj, [index]);
var getItem = type.GetMethod("get_Item", [typeof(int)]);
if (getItem != null)
getIndexedItemMethod = (obj, index) => getItem.Invoke(obj, [index]);
var setItem = type.GetMethod("set_Item", [typeof(int), ElementType]);
if (setItem != null)
setIndexedItemMethod = (obj, index, value) => setItem.Invoke(obj, [index, value]);
HasIndexerAccessors = getItem != null && setItem != null;
}
}
else
{
throw new ArgumentException($"Type [{type}] is not supported as a modifiable collection");
}
HasAdd = addMethod != null;
HasRemove = removeMethod != null;
HasInsert = insertMethod != null;
HasRemoveAt = removeAtMethod != null;
}
public override void Initialize(IComparer<object> keyComparer)
{
base.Initialize(keyComparer);
IsPureCollection = Count == 0;
}
public override DescriptorCategory Category => DescriptorCategory.Collection;
/// <summary>View on GitHub (pinned to 96fad776d2)