stride3d/stride · error · InvalidOperationException

The type of dictionary does not have a parameterless…

Error message

The type of dictionary does not have a parameterless constructor.

What it means

DictionaryWithIdsSerializer.CreatEmptyContainer constructs DictionaryWithItemIds<TKey,TValue> from the target dictionary's key/value types and requires a public parameterless constructor to instantiate it as the deserialization container. When the constructed generic type has no parameterless ctor, it throws InvalidOperationException, mirroring the collection-side guard.

Solutions

  1. Restore a public parameterless constructor on DictionaryWithItemIds<TKey,TValue>
  2. Fix the generic construction so key/value types match the intended concrete types
  3. Add linker/trimmer preservation for the parameterless constructor
  4. Ensure the asset member's declared dictionary type matches what the serializer expects

Example fix

// before (DictionaryWithItemIds.cs)
public DictionaryWithItemIds(IDictionary<TKey,TValue> source) { ... } // no parameterless ctor
// after
public DictionaryWithItemIds() { }
public DictionaryWithItemIds(IDictionary<TKey,TValue> source) { ... }
Defensive patterns

Strategy: validation

Validate before calling

var kvTypes = GetDictionaryKVTypes(myDictionaryType);
var containerType = typeof(DictionaryWithItemIds<,>).MakeGenericType(kvTypes.KeyType, kvTypes.ValueType);
if (containerType.GetConstructor(Type.EmptyTypes) == null)
    throw new InvalidOperationException($"{containerType} lost its parameterless ctor; fix before asset serialization");

Try / catch

try { SerializeAssets(stream, asset); }
catch (InvalidOperationException ex) when (ex.Message.Contains("parameterless constructor"))
{
    Log.Error("Dictionary serializer container broken: {Message}", ex.Message);
    throw;
}

Prevention

When it happens

Trigger: Deserializing an asset whose dictionary member leads to DictionaryWithItemIds<TKey,TValue> lacking a default ctor; source modifications removing the default constructor; trimming/AOT stripping the constructor; wrong KeyType/ValueType resolution building an unexpected generic instantiation.

Common situations: Custom asset dictionary members with exotic key/value types; patched Stride source; IL trimming in published editor builds breaking reflection-based activation.

Related errors


AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14). Data as JSON: /api/errors/63dc1373844307a0. Report an issue: GitHub.

Appendix: source

Thrown at sources/assets/Stride.Core.Assets/Yaml/DictionaryWithIdsSerializer.cs:87

            if (!identifier.TryGet(item.Key, out var id))
            {
                id = ItemId.New();
                identifier.Add(item.Key, id);
            }
            var keyWithId = Activator.CreateInstance(keyWithIdType, id, item.Key)!;
            instance.Add(keyWithId, item.Value);
        }

        return instance;
    }

    /// <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();

View on GitHub (pinned to 96fad776d2)