{"record":{"id":"e25fed95d94bef79","repo":"stride3d/stride","slug":"routingserializer-expected-in-the-chain-of-serializers","errorCode":null,"errorMessage":"RoutingSerializer expected in the chain of serializers","messagePattern":"RoutingSerializer expected in the chain of serializers","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"sources/assets/Stride.Core.Assets/Yaml/AssetYamlSerializer.cs","lineNumber":179,"sourceCode":"            if (serializer == null)\n            {\n                // var clock = Stopwatch.StartNew();\n\n                var config = new SerializerSettings\n                {\n                    EmitAlias = false,\n                    LimitPrimitiveFlowSequence = 0,\n                    Attributes = new AttributeRegistry(),\n                    PreferredIndent = 4,\n                    EmitShortTypeName = true,\n                    ComparerForKeySorting = new DefaultMemberComparer(),\n                    PreSerializer = new ContextAttributeSerializer(),\n                    PostSerializer = new ErrorRecoverySerializer(),\n                    SerializerFactorySelector = new ProfileSerializerFactorySelector(YamlSerializerFactoryAttribute.Default, \"Assets\"),\n                    ChainedSerializerFactory = x =>\n                    {\n                        var routingSerializer = x.FindNext<RoutingSerializer>()\n                            ?? throw new InvalidOperationException(\"RoutingSerializer expected in the chain of serializers\");\n                        // Prepend the IdentifiableObjectSerializer just before the routing serializer\n                        routingSerializer.Prepend(new IdentifiableObjectSerializer());\n                        // Prepend the ContextAttributeSerializer just before the routing serializer\n                        routingSerializer.Prepend(new ContextAttributeSerializer());\n                        // Prepend the ErrorRecoverySerializer at the beginning\n                        routingSerializer.First.Prepend(new ErrorRecoverySerializer());\n                    }\n                };\n\n                config.Attributes.PrepareMembersCallback += (objDesc, members) => PrepareMembersEvent?.Invoke(objDesc, members);\n\n                for (var index = RegisteredAssemblies.Count - 1; index >= 0; index--)\n                {\n                    var registeredAssembly = RegisteredAssemblies[index];\n                    config.RegisterAssembly(registeredAssembly);\n                }\n\n                var newSerializer = new Serializer(config);","sourceCodeStart":161,"sourceCodeEnd":197,"githubUrl":"https://github.com/stride3d/stride/blob/96fad776d210c221682aac1ccdf4c79dc046fc38/sources/assets/Stride.Core.Assets/Yaml/AssetYamlSerializer.cs#L161-L197","documentation":"During lazy initialization of the inner YAML serializer, EnsureYamlSerializer builds a serializer chain and requires a RoutingSerializer to be present via FindNext<RoutingSerializer>(). If the chain configuration (ChainedSerializerFactory) doesn't contain one, the library throws InvalidOperationException because it cannot prepend IdentifiableObjectSerializer/ContextAttributeSerializer/ErrorRecoverySerializer in the right places. This indicates a broken or altered serializer chain setup.","triggerScenarios":"Custom ChainedSerializerFactory or SerializerFactorySelector overrides that remove RoutingSerializer from the chain; modifying EnsureYamlSerializer's chain configuration in a fork; misconfigured YamlSerializerProfile that drops the routing stage.","commonSituations":"Patched Stride builds where the asset serializer chain was customized; third-party code replacing the chained-serializer factory for asset serialization; merge conflicts that dropped the FindNext<RoutingSerializer> wiring.","solutions":["Restore the default ChainedSerializerFactory configuration including RoutingSerializer in EnsureYamlSerializer","Ensure any custom chain factory inserts or preserves a RoutingSerializer","Compare your AssetYamlSerializer.cs against upstream Stride and reapply missing chain entries","Avoid overriding the serializer chain for asset serialization; use the profile selector instead"],"exampleFix":"// before\nChainedSerializerFactory = x => x.First.Prepend(new ErrorRecoverySerializer()); // no RoutingSerializer\n// after\nChainedSerializerFactory = x =>\n{\n    var routingSerializer = x.FindNext<RoutingSerializer>()\n        ?? throw new InvalidOperationException(\"RoutingSerializer expected in the chain of serializers\");\n    routingSerializer.Prepend(new IdentifiableObjectSerializer());\n    routingSerializer.Prepend(new ContextAttributeSerializer());\n    routingSerializer.First.Prepend(new ErrorRecoverySerializer());\n    return x;\n};","handlingStrategy":"try-catch","validationCode":"// only triggers on chain misconfiguration; validate your factory keeps RoutingSerializer\n// run one tiny serialize/deserialize at startup to fail fast:\nusing var ms = new MemoryStream();\nnew AssetYamlSerializer().Serialize(ms, dummyAsset);","typeGuard":null,"tryCatchPattern":"try { serializer.Serialize(stream, asset); }\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"RoutingSerializer\"))\n{\n    Log.Fatal(\"AssetYamlSerializer chain misconfigured: {Message}\", ex.Message);\n    throw; // configuration bug, not recoverable at runtime\n}","preventionTips":["Don't override ChainedSerializerFactory for asset serialization unless you replicate the full chain","Fail fast with a startup smoke-test of serialize/deserialize","Keep AssetYamlSerializer.cs aligned with upstream when rebasing forks","Add tests that exercise Serialize and Deserialize after any serializer-chain change"],"tags":["csharp","invalidoperationexception","yaml","serialization","internal"],"backgroundTag":"internal-invariant-violation","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"}