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
- Add a public parameterless constructor to the type
- Provide a private/protected empty ctor if you want to control instantiation (reflection invokes non-public ctors found by the scan)
- 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
- Give every referenceable/serializable type a parameterless constructor
- Re-check after adding parameterized ctors to existing types
- Add a unit test that instantiates all referencable types via CreateProxyObject
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
- The associated asset type does not have a public…
- The type of collection does not have a parameterless…
- The type of dictionary does not have a parameterless…
- Could not process serialization for member
- Unable to find property
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)