{"record":{"id":"2ac343da0ac11728","repo":"stride3d/stride","slug":"a-serializer-factory-selector-must-be-sealed-before-being","errorCode":null,"errorMessage":"A serializer factory selector must be sealed before being used.","messagePattern":"A serializer factory selector must be sealed before being used\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"sources/core/Stride.Core.Yaml/Serialization/SerializerFactorySelector.cs","lineNumber":40,"sourceCode":"        {\n            if (factory == null) throw new ArgumentNullException(nameof(factory));\n            if (isSealed) throw new InvalidOperationException(\"Cannot add a factory to a serializer factory selector once it is sealed.\");\n            if (CanAddSerializerFactory(factory))\n            {\n                factories.Add(factory);\n            }\n        }\n\n        /// <inheritdoc/>\n        public void Seal()\n        {\n            isSealed = true;\n        }\n\n        /// <inheritdoc/>\n        public IYamlSerializable GetSerializer(SerializerContext context, ITypeDescriptor typeDescriptor)\n        {\n            if (!isSealed) throw new InvalidOperationException(\"A serializer factory selector must be sealed before being used.\");\n            IYamlSerializable serializer;\n\n            // First try, with just a read lock\n            serializerLock.EnterReadLock();\n            var found = serializers.TryGetValue(typeDescriptor.Type, out serializer);\n            serializerLock.ExitReadLock();\n\n            if (!found)\n            {\n                // Not found, let's take exclusive lock and try again\n                serializerLock.EnterWriteLock();\n                if (!serializers.TryGetValue(typeDescriptor.Type, out serializer))\n                {\n                    foreach (var factory in factories)\n                    {\n                        serializer = factory.TryCreate(context, typeDescriptor);\n                        if (serializer != null)\n                        {","sourceCodeStart":22,"sourceCodeEnd":58,"githubUrl":"https://github.com/stride3d/stride/blob/96fad776d210c221682aac1ccdf4c79dc046fc38/sources/core/Stride.Core.Yaml/Serialization/SerializerFactorySelector.cs#L22-L58","documentation":"GetSerializer throws InvalidOperationException if the selector was not sealed before use. Sealing finalizes the factory list; using an unsealed selector could yield inconsistent serializer selection and break caching, so the library refuses to operate until Seal() is called.","triggerScenarios":"Calling GetSerializer(context, typeDescriptor) on a SerializerFactorySelector whose Seal() was never invoked — typically a selector built manually or wired into a Serializer without finishing registration/sealing.","commonSituations":"Custom serializer setup code that adds factories but forgets Seal(); DI-created selectors where no one calls Seal; partially completed initialization after an earlier exception aborted setup.","solutions":["Call Seal() on the selector after adding all factories and before any serialization/deserialization.","Ensure initialization completes even on error paths (try/finally or explicit init method).","Use the standard Serializer construction path that seals the selector automatically.","Check for swallowed exceptions earlier in setup that skipped the Seal call.","Guard usage: assert selector is sealed in your wrapper before serializing."],"exampleFix":"// before\nvar selector = new SerializerFactorySelector();\nselector.TryAddFactory(new MyFactory());\nserializer = new Serializer(selector); // GetSerializer later throws: not sealed\n// after\nvar selector = new SerializerFactorySelector();\nselector.TryAddFactory(new MyFactory());\nselector.Seal();\nserializer = new Serializer(selector);","handlingStrategy":"validation","validationCode":"// assert before use\nSystem.Diagnostics.Debug.Assert(selectorSealed, \"Call Seal() on the SerializerFactorySelector before serializing\");","typeGuard":null,"tryCatchPattern":"try { var s = selector.GetSerializer(ctx, descriptor); }\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"must be sealed\")) { throw new InvalidOperationException(\"Serializer was used before Seal() — finish initialization first\", ex); }","preventionTips":["Always call Seal() immediately after adding factories","Centralize serializer construction in one factory method that seals","Check initialization order in DI composition roots","Use the default Serializer constructor which handles sealing"],"tags":["yaml","invalid-operation","serializer-factory"],"backgroundTag":"invalid-state-transition","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"}