{"record":{"id":"269f73499f4e719b","repo":"stride3d/stride","slug":"the-last-chained-serializer-is-invoking-non-existing-next","errorCode":null,"errorMessage":"The last chained serializer is invoking non-existing next serializer","messagePattern":"The last chained serializer is invoking non-existing next serializer","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"sources/core/Stride.Core.Yaml/Serialization/Serializers/ChainedSerializer.cs","lineNumber":108,"sourceCode":"        /// </summary>\n        /// <param name=\"nextSerializer\">The serializer to append.</param>\n        public void Append([CanBeNull] ChainedSerializer nextSerializer)\n        {\n            // Update current Next if non-null to target the last of the chain we're appending\n            Next?.SetPrev(nextSerializer?.Last);\n            nextSerializer?.Last.SetNext(Next);\n            // Set the current Next to the given serializer\n            Next = nextSerializer;\n            // Make sure that the link with the old Prev of the given serializer is cleared\n            nextSerializer?.Prev?.SetNext(null);\n            // And set the Prev of the given serializer to be this one.\n            nextSerializer?.SetPrev(this);\n        }\n\n        /// <inheritdoc/>\n        public virtual object ReadYaml(ref ObjectContext objectContext)\n        {\n            if (Next == null) throw new InvalidOperationException(\"The last chained serializer is invoking non-existing next serializer\");\n            return Next.ReadYaml(ref objectContext);\n        }\n\n        /// <inheritdoc/>\n        public virtual void WriteYaml(ref ObjectContext objectContext)\n        {\n            if (Next == null) throw new InvalidOperationException(\"The last chained serializer is invoking non-existing next serializer\");\n            Next.WriteYaml(ref objectContext);\n        }\n\n        [NotNull]\n        private ChainedSerializer FindBoundary([NotNull] Func<ChainedSerializer, ChainedSerializer> navigate)\n        {\n            var current = this;\n            while (navigate(current) != null)\n            {\n                current = navigate(current);\n            }","sourceCodeStart":90,"sourceCodeEnd":126,"githubUrl":"https://github.com/stride3d/stride/blob/96fad776d210c221682aac1ccdf4c79dc046fc38/sources/core/Stride.Core.Yaml/Serialization/Serializers/ChainedSerializer.cs#L90-L126","documentation":"ChainedSerializer forwards ReadYaml to the next serializer in its chain. This error means the code invoked ReadYaml on a chained serializer that is the LAST link in the chain, so there is no next serializer to delegate to — a broken/incorrectly assembled serializer chain.","triggerScenarios":"Calling ReadYaml (directly or via ObjectContext) on a ChainedSerializer that was constructed with no next serializer, or whose chain was mis-assembled so the terminal node is asked to delegate instead of doing real work.","commonSituations":"Custom serialization setups registering a ChainedSerializer without appending it to a real serializer; serialization service factory changes/upgrades altering chain composition; manually building serializer chains in tests.","solutions":["Check how the ChainedSerializer was registered/constructed and ensure it is appended after a concrete terminal serializer (e.g. ObjectSerializer/PrimitiveSerializer)","Rebuild the serializer chain via the standard SerializerFactory instead of hand-assembling links","Inspect ChainedSerializer.Next before invoking ReadYaml in custom code and handle the null case","Update/fix custom ISerializerFactory plugins that modify the chain ordering"],"exampleFix":"// before\nvar chained = new ChainedSerializer();\nchained.ReadYaml(ref objectContext); // throws: chain ends here\n// after\nvar chained = new ChainedSerializer(new ObjectSerializer());\nchained.ReadYaml(ref objectContext); // delegates to real serializer","handlingStrategy":"try-catch","validationCode":"if (serializer is ChainedSerializer cs && cs.Next == null)\n    throw new InvalidOperationException(\"Chained serializer has no next serializer; assemble the chain first\");","typeGuard":"static bool HasNext(ChainedSerializer s) => s?.Next != null;","tryCatchPattern":"try\n{\n    chained.ReadYaml(ref objectContext);\n}\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"non-existing next serializer\"))\n{\n    // fall back to the concrete serializer for this type\n}","preventionTips":["Always append chained serializers after a concrete terminal serializer","Assemble chains via SerializerFactory rather than manually","Unit-test custom serializer chains for both read and write paths"],"tags":["yaml","serialization","serializer-chain"],"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-23T08:17:48.524Z"}