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
- 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
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
- 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
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
- Event handlers can't be added or removed after the serialize
- The type of collection does not have a parameterless constru
- The given container does not match the expected type.
- The type of dictionary does not have a parameterless constru
- The order of the Asset.Id property must be lower than the or
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)