stride3d/stride · error · InvalidOperationException

Incompatible serializer found for same type in different…

Error message

Incompatible serializer found for same type in different assemblies for {0}

What it means

AddSerializableType throws when the same data type already has a registered serializer with a different DataSerializerGenericMode, meaning two assemblies contributed incompatible serializers for the same type. The processor cannot pick one mode, so registration fails.

Solutions

  1. Remove or de-duplicate the conflicting DataSerializer so only one remains for that type
  2. Align the DataSerializerGenericMode on both serializer declarations
  3. Exclude one of the assemblies from the assembly processor
  4. If in Stride source, resolve the TODO for the generic case in AddSerializableType

Example fix

// before
// AssemblyA
[DataSerializerGenericMode(DataSerializerGenericMode.None)]
class VecSerializer : DataSerializer<MyVec> {}
// AssemblyB
[DataSerializerGenericMode(DataSerializerGenericMode.GenericArityAndArguments)]
class VecSerializer2 : DataSerializer<MyVec> {}
// after
// keep exactly one:
[DataSerializerGenericMode(DataSerializerGenericMode.None)]
class VecSerializer : DataSerializer<MyVec> {}
Defensive patterns

Strategy: validation

Validate before calling

// Ensure only one serializer exists per data type across referenced assemblies:
var seen = new Dictionary<Type, Type>();
foreach (var asm in referencedAssemblies)
    foreach (var s in asm.GetTypes().Where(t => typeof(DataSerializer).IsAssignableFrom(t) && !t.IsAbstract))
    {
        var dataType = GetSerializedType(s);
        if (seen.TryGetValue(dataType, out var dup))
            Console.WriteLine($"[conflict] {dup.Name} vs {s.Name} both serialize {dataType.Name}");
        else seen[dataType] = s;
    }

Try / catch

try { RegisterSerializer(type); }
catch (InvalidOperationException ex) when (ex.Message.StartsWith("Incompatible serializer found"))
{
    logger.Warn($"Duplicate serializer for {type}: keeping existing registration");
}

Prevention

When it happens

Trigger: Two assemblies register serializers for the same dataType with different generic modes (currentValue.Mode != serializableTypeInfo.Mode), e.g. one [DataSerializer] without generic mode and another with GenericArityAndArguments.

Common situations: Referencing two plugin/game assemblies that each define a serializer for a shared type; a package upgrade introduces a duplicate serializer; partial copy-paste of a serializer into a second assembly.

Understand the failure class

Background: Conflicting config options: "cannot be used together" — configuration validation errors across open-source libraries — this error's family across 162 libraries.

Related errors


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

Appendix: source

Thrown at sources/core/Stride.Core.AssemblyProcessor/Serializers/CecilSerializerContext.cs:462

    }

    public void AddSerializableType(TypeReference dataType, SerializableTypeInfo serializableTypeInfo, string profile = "Default")
    {
        // Check if declaring type is generics
        var resolvedType = dataType.Resolve();
        if (resolvedType?.DeclaringType != null && (resolvedType.HasGenericParameters || resolvedType.DeclaringType.HasGenericParameters))
        {
            throw new NotSupportedException(string.Format("Serialization of nested types referencing parent's generic parameters is not currently supported. " +
                                                          "[Nested type={0} Parent={1}]", resolvedType.FullName, resolvedType.DeclaringType));
        }

        var profileInfo = GetSerializableTypes(profile);

        if (profileInfo.TryGetSerializableTypeInfo(dataType, serializableTypeInfo.Mode != DataSerializerGenericMode.None, out var currentValue))
        {
            // TODO: Doesn't work in some generic case
            if (currentValue.Mode != serializableTypeInfo.Mode)
                throw new InvalidOperationException(string.Format("Incompatible serializer found for same type in different assemblies for {0}", dataType.ConvertCSharp()));
            return;
        }

        // Check that we don't simply try to add the same serializer than Default profile (optimized)
        if (profile != "Default" && SerializableTypes.TryGetSerializableTypeInfo(dataType, serializableTypeInfo.Mode != DataSerializerGenericMode.None, out var defaultValue))
        {
            if (defaultValue.SerializerType.FullName == serializableTypeInfo.SerializerType.FullName)
            {
                // Already added in default profile, early exit
                return;
            }
        }

        profileInfo.AddSerializableTypeInfo(dataType, serializableTypeInfo);

        // Scan and add dependencies (stored in EnumerateGenericInstantiations() methods)
        ScanSerializerDependencies(dataType, serializableTypeInfo);
    }

View on GitHub (pinned to 96fad776d2)