stride3d/stride · error · InvalidOperationException
The given container does not match the expected type.
Error message
The given container does not match the expected type.
What it means
DictionaryWithIdsSerializer transforms a deserialized IDictionary container into a DictionaryWithItemIds<Key,Value> instance. This InvalidOperationException is thrown when the container object produced by deserialization is not actually an instance of the constructed DictionaryWithItemIds<,> generic type, meaning the deserializer's internal invariants were violated.
Solutions
- Ensure the container passed to TransformAfterDeserialization is created via the DictionaryWithIdsSerializer/WithIds pipeline so it is a DictionaryWithItemIds<Key,Value>
- Verify the target type descriptor's KeyType/ValueType match the container's generic arguments
- Check that no custom ITypeDescriptor or serializer factory substitutes a plain dictionary for with-ids dictionaries
- Regenerate the asset YAML with a compatible Stride version instead of hand-editing serialized collections
Example fix
// before (custom serializer yields plain dictionary)
var container = new Dictionary<string, MyItem>();
serializer.TransformAfterDeserialization(container, descriptor, target);
// after
var container = (IDictionary)Activator.CreateInstance(
typeof(DictionaryWithItemIds<,>).MakeGenericType(descriptor.KeyType, descriptor.ValueType));
serializer.TransformAfterDeserialization(container, descriptor, target); Defensive patterns
Strategy: validation
Validate before calling
var expected = typeof(DictionaryWithItemIds<,>).MakeGenericType(descriptor.KeyType, descriptor.ValueType);
if (!expected.IsInstanceOfType(container)) throw new InvalidOperationException("Container type mismatch before transform"); Type guard
bool IsValidContainer(IDictionary c, DictionaryDescriptor d) =>
typeof(DictionaryWithItemIds<,>).MakeGenericType(d.KeyType, d.ValueType).IsInstanceOfType(c); Try / catch
try { serializer.TransformAfterDeserialization(container, descriptor, target); }
catch (InvalidOperationException ex) { logger.Error(ex, "Dictionary container type mismatch"); throw; } Prevention
- Let the Stride serializer create dictionary containers; never substitute plain Dictionary
- Keep key/value types consistent between descriptor and container
- Avoid hand-editing serialized with-ids collections in YAML assets
When it happens
Trigger: Calling TransformObjectAfterRead during YAML asset deserialization when the IDictionary container handed to TransformAfterDeserialization was created by a different serializer or is a plain Dictionary/other IDictionary implementation instead of DictionaryWithItemIds<Key,Value> for the target descriptor's key/value types.
Common situations: Custom YAML serializers or hand-written deserialization pipelines feeding non-standard dictionary containers; a mismatch between the target descriptor's key/value types and the actual container type after a type or asset-schema version change; corrupted or hand-edited asset YAML producing unexpected collection types.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- ex.Message
- ex.Message
- Multiple identifiable objects with the same id
- Unable to decode asset part reference
- Unable to deserialize reference
AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14).
Data as JSON: /api/errors/3dfefb90b23a4914.
Report an issue: GitHub.
Appendix: source
Thrown at sources/assets/Stride.Core.Assets/Yaml/DictionaryWithIdsSerializer.cs:97
}
/// <inheritdoc/>
protected override IDictionary CreatEmptyContainer(ITypeDescriptor descriptor)
{
var dictionaryDescriptor = (DictionaryDescriptor)descriptor;
var type = typeof(DictionaryWithItemIds<,>).MakeGenericType(dictionaryDescriptor.KeyType, dictionaryDescriptor.ValueType);
if (type.GetConstructor(Type.EmptyTypes) == null)
throw new InvalidOperationException("The type of dictionary does not have a parameterless constructor.");
return (IDictionary)Activator.CreateInstance(type)!;
}
/// <inheritdoc/>
protected override void TransformAfterDeserialization(IDictionary container, ITypeDescriptor targetDescriptor, object targetCollection, ICollection<ItemId>? deletedItems = null)
{
var dictionaryDescriptor = (DictionaryDescriptor)targetDescriptor;
var type = typeof(DictionaryWithItemIds<,>).MakeGenericType(dictionaryDescriptor.KeyType, dictionaryDescriptor.ValueType);
if (!type.IsInstanceOfType(container))
throw new InvalidOperationException("The given container does not match the expected type.");
var identifier = CollectionItemIdHelper.GetCollectionItemIds(targetCollection);
identifier.Clear();
// The collection may contain some initial data from its containing instance's ctor,
// let's replace the existing data with the data we have serialized
dictionaryDescriptor.Clear(targetCollection);
var enumerator = container.GetEnumerator();
while (enumerator.MoveNext())
{
var keyWithId = (IKeyWithId)enumerator.Key;
dictionaryDescriptor.AddToDictionary(targetCollection, keyWithId.Key, enumerator.Value);
identifier.Add(keyWithId.Key, keyWithId.Id);
}
if (deletedItems != null)
{
foreach (var deletedItem in deletedItems)
{View on GitHub (pinned to 96fad776d2)