stride3d/stride · error · InvalidOperationException
The last chained serializer is invoking non-existing next…
Error message
The last chained serializer is invoking non-existing next serializer
What it means
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.
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
Example fix
// before var chained = new ChainedSerializer(); chained.ReadYaml(ref objectContext); // throws: chain ends here // after var chained = new ChainedSerializer(new ObjectSerializer()); chained.ReadYaml(ref objectContext); // delegates to real serializer
Defensive patterns
Strategy: try-catch
Validate before calling
if (serializer is ChainedSerializer cs && cs.Next == null)
throw new InvalidOperationException("Chained serializer has no next serializer; assemble the chain first"); Type guard
static bool HasNext(ChainedSerializer s) => s?.Next != null;
Try / catch
try
{
chained.ReadYaml(ref objectContext);
}
catch (InvalidOperationException ex) when (ex.Message.Contains("non-existing next serializer"))
{
// fall back to the concrete serializer for this type
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- Aliases are not supported in JSON
- At least one profile must be specified.
- Attributes can not be null
- Duplicate %TAG directive.
- Event handlers can't be added or removed after the…
AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14).
Data as JSON: /api/errors/269f73499f4e719b.
Report an issue: GitHub.
Appendix: source
Thrown at sources/core/Stride.Core.Yaml/Serialization/Serializers/ChainedSerializer.cs:108
/// </summary>
/// <param name="nextSerializer">The serializer to append.</param>
public void Append([CanBeNull] ChainedSerializer nextSerializer)
{
// Update current Next if non-null to target the last of the chain we're appending
Next?.SetPrev(nextSerializer?.Last);
nextSerializer?.Last.SetNext(Next);
// Set the current Next to the given serializer
Next = nextSerializer;
// Make sure that the link with the old Prev of the given serializer is cleared
nextSerializer?.Prev?.SetNext(null);
// And set the Prev of the given serializer to be this one.
nextSerializer?.SetPrev(this);
}
/// <inheritdoc/>
public virtual object ReadYaml(ref ObjectContext objectContext)
{
if (Next == null) throw new InvalidOperationException("The last chained serializer is invoking non-existing next serializer");
return Next.ReadYaml(ref objectContext);
}
/// <inheritdoc/>
public virtual void WriteYaml(ref ObjectContext objectContext)
{
if (Next == null) throw new InvalidOperationException("The last chained serializer is invoking non-existing next serializer");
Next.WriteYaml(ref objectContext);
}
[NotNull]
private ChainedSerializer FindBoundary([NotNull] Func<ChainedSerializer, ChainedSerializer> navigate)
{
var current = this;
while (navigate(current) != null)
{
current = navigate(current);
}View on GitHub (pinned to 96fad776d2)