{"record":{"id":"ff7150301a9aeca8","repo":"stride3d/stride","slug":"a-reference-can-only-be-constructed-with-the-method","errorCode":null,"errorMessage":"A reference can only be constructed with the method Reference.CreateReference","messagePattern":"A reference can only be constructed with the method Reference\\.CreateReference","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"sources/presentation/Stride.Core.Quantum/References/Reference.cs","lineNumber":54,"sourceCode":"            {\n                reference = null;\n            }\n        }\n\n        --CreatingReference.Value;\n\n        return reference;\n    }\n\n    private static bool HasCollectionReference(Type type)\n    {\n        return type.IsArray || ListDescriptor.IsList(type) || DictionaryDescriptor.IsDictionary(type) || SetDescriptor.IsSet(type) || CollectionDescriptor.IsCollection(type);\n    }\n\n    internal static void CheckReferenceCreationSafeGuard()\n    {\n        if (!CreatingReference.IsValueCreated || CreatingReference.Value == 0)\n            throw new InvalidOperationException(\"A reference can only be constructed with the method Reference.CreateReference\");\n    }\n}\n","sourceCodeStart":36,"sourceCodeEnd":57,"githubUrl":"https://github.com/stride3d/stride/blob/96fad776d210c221682aac1ccdf4c79dc046fc38/sources/presentation/Stride.Core.Quantum/References/Reference.cs#L36-L57","documentation":"Reference constructors require an internal thread-local counter (CreatingReference) to be active; it is incremented only inside Reference.CreateReference. If a Reference-derived object is constructed directly (new ...) outside that factory, CheckReferenceCreationSafeGuard detects the counter is zero and throws InvalidOperationException, enforcing that every reference is created through the factory.","triggerScenarios":"Instantiating Reference (or a subclass such as ReferenceEnumerable) directly with `new`, instead of calling Reference.CreateReference; this typically happens in custom factories or tests bypassing the factory.","commonSituations":"Writing a custom IReference implementation or NodeFactory; unit tests constructing ReferenceEnumerable to inspect item references; code copied from older Stride versions where direct construction was tolerated.","solutions":["Replace direct construction (new ReferenceEnumerable(...)/new DerivedReference(...)) with a call to Reference.CreateReference.","If you need collection semantics, pass a value of a list/dictionary/set/collection type to CreateReference so it produces a ReferenceEnumerable.","Only call the constructor from within Reference.CreateReference (i.e. subclass code inside the library)."],"exampleFix":"// before\nvar reference = new ReferenceEnumerable(value, nodeIndex);\n// after\nvar reference = (ReferenceEnumerable)Reference.CreateReference(value, value.GetType(), nodeIndex, false);","handlingStrategy":"type-guard","validationCode":"var reference = value != null ? Reference.CreateReference(value, value.GetType(), index, isMember) : null;","typeGuard":"bool SafeToConstruct() => Reference.CheckReferenceCreationSafeGuard is only satisfied inside CreateReference; never call constructors directly — always use Reference.CreateReference.","tryCatchPattern":"try { var r = Reference.CreateReference(value, type, index, isMember); }\ncatch (InvalidOperationException) { /* you bypassed the factory; switch to CreateReference */ }","preventionTips":["Treat Reference constructors as internal-only; always use Reference.CreateReference","Audit custom NodeFactories/tests for direct `new Reference...`","Reference obsolete API warnings — the factory contract is enforced by this guard"],"tags":["internal-invariant","quantum","misuse-of-api"],"backgroundTag":"invalid-constructor-argument","analyzedSha":"96fad776d210c221682aac1ccdf4c79dc046fc38","analyzedAt":"2026-09-14T02:59:31.279Z","contentChangedAt":"2026-09-14T02:59:31.279Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}