stride3d/stride · error · NotSupportedException

Serialization of nested types referencing parent's generic…

Error message

Serialization of nested types referencing parent's generic parameters is not currently supported. [Nested type={0} Parent={1}]

What it means

AddSerializableType rejects nested types that reference their declaring (parent) type's generic parameters, because the assembly processor cannot generate serializers for such open-nested generics. This is an explicit NotSupported limitation of the codegen.

Solutions

  1. Move the nested type out of the generic parent to top-level scope
  2. Remove the dependency on the parent's generic parameters (replace T with a concrete type)
  3. If generic behavior is needed, make the nested type itself generic and use a dedicated DataSerializer
  4. Wrap the data in a non-generic container type instead

Example fix

// before
public class Container<T>
{
    public class Item { public T Value; } // nested, references T
}
// after
public class ContainerItem<T>
{
    public T Value;
}
public class Container<T> { ... }
Defensive patterns

Strategy: validation

Validate before calling

static void EnsureNotGenericNested(Type t)
{
    if (t.IsNested && (t.ContainsGenericParameters || t.DeclaringType.ContainsGenericParameters))
        throw new InvalidOperationException($"{t.FullName} must not be nested in a generic type");
}

Type guard

static bool IsUnsupportedNestedGeneric(Type t) =>
    t.IsNested && (t.ContainsGenericParameters || t.DeclaringType.ContainsGenericParameters);

Prevention

When it happens

Trigger: Any of ResolveSerializer/FindSerializerInfo/ProcessDataSerializerAttribute etc. calls AddSerializableType with a nested type whose own or whose declaring type HasGenericParameters is true (e.g. class Outer<T> { class Inner { public T Value; } }).

Common situations: Declaring a data contract nested inside a generic class; moving a serializable class inside a generic wrapper during refactoring.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


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

Appendix: source

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

                IsPublic = type.HasGenericParameters,
                UseClassDataSerializer = useClassDataSerializer,
                SerializableTypeInfo = serializableTypeInfo,
            };
            PendingSerializers.Add(descriptor);
        }

        serializableTypeInfo.IsGeneratedSerializer = true;

        return (serializableTypeInfo, descriptor);
    }

    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)
            {

View on GitHub (pinned to 96fad776d2)