{"record":{"id":"206b84cc8abc3c17","repo":"stride3d/stride","slug":"type-type-has-no-empty-ctor","errorCode":null,"errorMessage":"Type {type} has no empty ctor","messagePattern":"Type (.+?) has no empty ctor","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"sources/core/Stride.Core.Serialization/Serialization/AttachedReferenceManager.cs","lineNumber":114,"sourceCode":"    /// <param name=\"location\">The location.</param>\n    public static object CreateProxyObject([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] Type type, AssetId id, string location)\n    {\n        ConstructorInfo? emptyCtor;\n        lock (EmptyCtorCache)\n        {\n            if (!EmptyCtorCache.TryGetValue(type, out emptyCtor))\n            {\n                foreach (var ctor in type.GetTypeInfo().DeclaredConstructors)\n                {\n                    if (!ctor.IsStatic && ctor.GetParameters().Length == 0)\n                    {\n                        emptyCtor = ctor;\n                        break;\n                    }\n                }\n                if (emptyCtor == null)\n                {\n                    throw new InvalidOperationException($\"Type {type} has no empty ctor\");\n                }\n                EmptyCtorCache.Add(type, emptyCtor);\n            }\n        }\n        var result = emptyCtor.Invoke(EmptyObjectArray);\n        InitializeProxyObject(result, id, location);\n        return result;\n    }\n    private static void InitializeProxyObject(object proxyObject, AssetId id, string location)\n    {\n        var attachedReference = GetOrCreateAttachedReference(proxyObject);\n        attachedReference.Id = id;\n        attachedReference.Url = location;\n        attachedReference.IsProxy = true;\n    }\n}\n","sourceCodeStart":96,"sourceCodeEnd":131,"githubUrl":"https://github.com/stride3d/stride/blob/96fad776d210c221682aac1ccdf4c79dc046fc38/sources/core/Stride.Core.Serialization/Serialization/AttachedReferenceManager.cs#L96-L131","documentation":"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.","triggerScenarios":"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.","commonSituations":"Custom serializable/referenceable types authored without a default constructor; adding a ctor with arguments to a previously parameterless class breaks proxy creation at runtime.","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"],"exampleFix":"// before\npublic class MyEntity\n{\n    public MyEntity(string name) { ... }\n}\n// after\npublic class MyEntity\n{\n    public MyEntity() { }\n    public MyEntity(string name) { ... }\n}","handlingStrategy":"try-catch","validationCode":"static bool CanCreateProxy(Type type) =>\n    type.GetConstructors(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)\n        .Any(c => c.GetParameters().Length == 0);","typeGuard":"bool IsProxyCompatible(Type t) =>\n    t.GetConstructors(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)\n     .Any(c => c.GetParameters().Length == 0);","tryCatchPattern":"try { var proxy = AttachedReferenceManager.CreateProxyObject(type, id, url); }\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"has no empty ctor\"))\n{\n    Log.Error($\"{type.Name} must define a parameterless constructor\");\n}","preventionTips":["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"],"tags":["reflection","serialization","constructor"],"backgroundTag":"missing-default-constructor","analyzedSha":"96fad776d210c221682aac1ccdf4c79dc046fc38","analyzedAt":"2026-09-14T02:59:31.279Z","contentChangedAt":"2026-09-14T02:59:31.279Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}