stride3d/stride · error · InvalidOperationException

RoutingSerializer expected in the chain of serializers

Error message

RoutingSerializer expected in the chain of serializers

What it means

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.

Solutions

  1. Restore the default ChainedSerializerFactory configuration including RoutingSerializer in EnsureYamlSerializer
  2. Ensure any custom chain factory inserts or preserves a RoutingSerializer
  3. Compare your AssetYamlSerializer.cs against upstream Stride and reapply missing chain entries
  4. Avoid overriding the serializer chain for asset serialization; use the profile selector instead

Example fix

// before
ChainedSerializerFactory = x => x.First.Prepend(new ErrorRecoverySerializer()); // no RoutingSerializer
// after
ChainedSerializerFactory = x =>
{
    var routingSerializer = x.FindNext<RoutingSerializer>()
        ?? throw new InvalidOperationException("RoutingSerializer expected in the chain of serializers");
    routingSerializer.Prepend(new IdentifiableObjectSerializer());
    routingSerializer.Prepend(new ContextAttributeSerializer());
    routingSerializer.First.Prepend(new ErrorRecoverySerializer());
    return x;
};
Defensive patterns

Strategy: try-catch

Validate before calling

// only triggers on chain misconfiguration; validate your factory keeps RoutingSerializer
// run one tiny serialize/deserialize at startup to fail fast:
using var ms = new MemoryStream();
new AssetYamlSerializer().Serialize(ms, dummyAsset);

Try / catch

try { serializer.Serialize(stream, asset); }
catch (InvalidOperationException ex) when (ex.Message.Contains("RoutingSerializer"))
{
    Log.Fatal("AssetYamlSerializer chain misconfigured: {Message}", ex.Message);
    throw; // configuration bug, not recoverable at runtime
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

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


AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14). Data as JSON: /api/errors/e25fed95d94bef79. Report an issue: GitHub.

Appendix: source

Thrown at sources/assets/Stride.Core.Assets/Yaml/AssetYamlSerializer.cs:179

            if (serializer == null)
            {
                // var clock = Stopwatch.StartNew();

                var config = new SerializerSettings
                {
                    EmitAlias = false,
                    LimitPrimitiveFlowSequence = 0,
                    Attributes = new AttributeRegistry(),
                    PreferredIndent = 4,
                    EmitShortTypeName = true,
                    ComparerForKeySorting = new DefaultMemberComparer(),
                    PreSerializer = new ContextAttributeSerializer(),
                    PostSerializer = new ErrorRecoverySerializer(),
                    SerializerFactorySelector = new ProfileSerializerFactorySelector(YamlSerializerFactoryAttribute.Default, "Assets"),
                    ChainedSerializerFactory = x =>
                    {
                        var routingSerializer = x.FindNext<RoutingSerializer>()
                            ?? throw new InvalidOperationException("RoutingSerializer expected in the chain of serializers");
                        // Prepend the IdentifiableObjectSerializer just before the routing serializer
                        routingSerializer.Prepend(new IdentifiableObjectSerializer());
                        // Prepend the ContextAttributeSerializer just before the routing serializer
                        routingSerializer.Prepend(new ContextAttributeSerializer());
                        // Prepend the ErrorRecoverySerializer at the beginning
                        routingSerializer.First.Prepend(new ErrorRecoverySerializer());
                    }
                };

                config.Attributes.PrepareMembersCallback += (objDesc, members) => PrepareMembersEvent?.Invoke(objDesc, members);

                for (var index = RegisteredAssemblies.Count - 1; index >= 0; index--)
                {
                    var registeredAssembly = RegisteredAssemblies[index];
                    config.RegisterAssembly(registeredAssembly);
                }

                var newSerializer = new Serializer(config);

View on GitHub (pinned to 96fad776d2)