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

  1. Ensure the container passed to TransformAfterDeserialization is created via the DictionaryWithIdsSerializer/WithIds pipeline so it is a DictionaryWithItemIds<Key,Value>
  2. Verify the target type descriptor's KeyType/ValueType match the container's generic arguments
  3. Check that no custom ITypeDescriptor or serializer factory substitutes a plain dictionary for with-ids dictionaries
  4. 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

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


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)