stride3d/stride · error · InvalidOperationException

Could not find serializer for type

Error message

Could not find serializer for type {typeof(T)}.

What it means

This generic extension method on SerializationStream fetches the DataSerializer for T from the context's SerializerSelector and throws InvalidOperationException when none is registered. Unlike the internal code paths this is a public convenience API, so callers hitting it serialized a type that simply has no serializer available in the current serialization context.

Solutions

  1. Ensure the type is [DataContract] (or has a [DataSerializer]) and rebuild so generated serializers are registered
  2. Check stream.Context.SerializerSelector and use the default selector that includes the serializer for T
  3. Register T's assembly via Serialization.RegisterSerializationAssembly before serializing
  4. Write and register a custom DataSerializer for types you cannot annotate
  5. Catch InvalidOperationException and log typeof(T) to identify which type lacks a serializer

Example fix

// before
stream.Serialize(ref customThing); // InvalidOperationException: no serializer
// after
public class CustomThingSerializer : DataSerializer<CustomThing>
{ /* implement Serialize/Deserialize */ }
// register it, or mark CustomThing [DataContract] and rebuild
Defensive patterns

Strategy: try-catch

Validate before calling

var selector = stream.Context.SerializerSelector;
if (selector.GetSerializer<T>() == null)
    throw new InvalidOperationException($"Before calling Serialize, register a serializer for {typeof(T)}");

Type guard

static bool HasSerializerFor<T>(SerializationStream stream) =>
    stream.Context.SerializerSelector.GetSerializer<T>() is not null;

Try / catch

try
{
    stream.Serialize(ref value);
}
catch (InvalidOperationException ex) when (ex.Message.Contains("Could not find serializer for type"))
{
    logger.Error(ex, "No serializer registered for {Type}; add [DataContract]/[DataSerializer] or fix the SerializerSelector", typeof(T));
    throw;
}

Prevention

When it happens

Trigger: Calling stream.Serialize(ref myObj) (or Write) for a type T without a [DataContract]/generated or custom serializer; a custom SerializerSelector attached to the SerializationContext that excludes T's serializer; serializing before assembly registration of T's module; serializing unannotated third-party types.

Common situations: Quick custom binary save code writing component fields directly with stream.Serialize; serializing enums/structs from an assembly without generated serializers; swapping in a restricted SerializerSelector for partial serialization and forgetting the needed type; unit tests constructing a SerializationStream without the default selector.

Related errors


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

Appendix: source

Thrown at sources/core/Stride.Core/Serialization/SerializerExtensions.cs:93

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public static void Write<T>(this SerializationStream stream, T obj)
    {
        Serialize(stream, ref obj, ArchiveMode.Serialize);
    }

    /// <summary>
    /// Serializes the specified object.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="stream">The stream to serialize to.</param>
    /// <param name="obj">The object to serialize.</param>
    /// <param name="mode">The serialization mode.</param>
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public static void Serialize<T>(this SerializationStream stream, ref T obj, ArchiveMode mode)
    {
        var dataSerializer = stream.Context.SerializerSelector.GetSerializer<T>();
        if (dataSerializer == null)
            throw new InvalidOperationException($"Could not find serializer for type {typeof(T)}.");

        dataSerializer.PreSerialize(ref obj, mode, stream);
        dataSerializer.Serialize(ref obj, mode, stream);
    }

    /// <summary>Serializes or deserializes the value using <see cref="SerializationStream.Serialize(Span{byte})"/>.</summary>
    public static void Serialize<T>(this SerializationStream serializer, ref T value)
    {
        ref var b = ref Unsafe.As<T, byte>(ref value);
        var span = MemoryMarshal.CreateSpan(ref b, Unsafe.SizeOf<T>());
        serializer.Serialize(span);
    }

    /// <summary>
    /// Reads a boolean value from the stream.
    /// </summary>
    /// <param name="stream">The stream.</param>
    /// <returns>A boolean value read from the stream.</returns>

View on GitHub (pinned to 96fad776d2)