stride3d/stride · error · InvalidOperationException

Type has no empty ctor

Error message

Type {type} has no empty ctor

What it means

AttachedReferenceManager.CreateProxyObject creates a proxy instance of a type that implements IReferencable/attached-reference semantics. It needs a parameterless constructor (found via reflection and cached in EmptyCtorCache); if the type declares no empty ctor it cannot be instantiated as a proxy, so it throws InvalidOperationException.

Solutions

  1. Add a public parameterless constructor to the type
  2. Provide a private/protected empty ctor if you want to control instantiation (reflection invokes non-public ctors found by the scan)
  3. Stop using attached references for that type and manage identity manually

Example fix

// before
public class MyEntity
{
    public MyEntity(string name) { ... }
}
// after
public class MyEntity
{
    public MyEntity() { }
    public MyEntity(string name) { ... }
}
Defensive patterns

Strategy: try-catch

Validate before calling

static bool CanCreateProxy(Type type) =>
    type.GetConstructors(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
        .Any(c => c.GetParameters().Length == 0);

Type guard

bool IsProxyCompatible(Type t) =>
    t.GetConstructors(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
     .Any(c => c.GetParameters().Length == 0);

Try / catch

try { var proxy = AttachedReferenceManager.CreateProxyObject(type, id, url); }
catch (InvalidOperationException ex) when (ex.Message.Contains("has no empty ctor"))
{
    Log.Error($"{type.Name} must define a parameterless constructor");
}

Prevention

When it happens

Trigger: Attaching an ObjectReference to (or resolving a URL for) a type whose constructors all require parameters, e.g. a class with only CustomType(params) ctors.

Common situations: Custom serializable/referenceable types authored without a default constructor; adding a ctor with arguments to a previously parameterless class breaks proxy creation at runtime.

Related errors


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

Appendix: source

Thrown at sources/core/Stride.Core.Serialization/Serialization/AttachedReferenceManager.cs:114

    /// <param name="location">The location.</param>
    public static object CreateProxyObject([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] Type type, AssetId id, string location)
    {
        ConstructorInfo? emptyCtor;
        lock (EmptyCtorCache)
        {
            if (!EmptyCtorCache.TryGetValue(type, out emptyCtor))
            {
                foreach (var ctor in type.GetTypeInfo().DeclaredConstructors)
                {
                    if (!ctor.IsStatic && ctor.GetParameters().Length == 0)
                    {
                        emptyCtor = ctor;
                        break;
                    }
                }
                if (emptyCtor == null)
                {
                    throw new InvalidOperationException($"Type {type} has no empty ctor");
                }
                EmptyCtorCache.Add(type, emptyCtor);
            }
        }
        var result = emptyCtor.Invoke(EmptyObjectArray);
        InitializeProxyObject(result, id, location);
        return result;
    }
    private static void InitializeProxyObject(object proxyObject, AssetId id, string location)
    {
        var attachedReference = GetOrCreateAttachedReference(proxyObject);
        attachedReference.Id = id;
        attachedReference.Url = location;
        attachedReference.IsProxy = true;
    }
}

View on GitHub (pinned to 96fad776d2)