{"record":{"id":"b73a99c100cefc6e","repo":"stride3d/stride","slug":"can-t-deduce-data-serializer-type-for-generic-types","errorCode":null,"errorMessage":"Can't deduce data serializer type for generic types.","messagePattern":"Can't deduce data serializer type for generic types\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"sources/core/Stride.Core.AssemblyProcessor/Serializers/ReferencedAssemblySerializerProcessor.cs","lineNumber":72,"sourceCode":"        // Find DataSerializer attribute on assembly and/or types\n        foreach (var dataSerializerAttribute in\n            assembly.CustomAttributes.Concat(assembly.MainModule.GetAllTypes().SelectMany(x => x.CustomAttributes)).Where(\n                x => x.AttributeType.FullName == \"Stride.Core.Serialization.DataSerializerGlobalAttribute\")\n                .OrderBy(x => x.ConstructorArguments[0].Value != null ? -1 : 1)) // Order so that we first have the ones which don't require us to go through GenerateSerializer\n        {\n            var dataSerializerType = (TypeReference)dataSerializerAttribute.ConstructorArguments[0].Value;\n            var dataType = (TypeReference)dataSerializerAttribute.ConstructorArguments[1].Value;\n            var mode = (DataSerializerGenericMode)dataSerializerAttribute.ConstructorArguments[2].Value;\n            var inherited = (bool)dataSerializerAttribute.ConstructorArguments[3].Value;\n            var complexSerializer = (bool)dataSerializerAttribute.ConstructorArguments[4].Value;\n            var profile = dataSerializerAttribute.Properties.Where(x => x.Name == \"Profile\").Select(x => (string)x.Argument.Value).FirstOrDefault() ?? \"Default\";\n\n            if (dataType == null)\n            {\n                if (mode == DataSerializerGenericMode.None)\n                    dataType = FindSerializerDataType(dataSerializerType);\n                else\n                    throw new InvalidOperationException(\"Can't deduce data serializer type for generic types.\");\n            }\n\n            // Reading from custom arguments doesn't have its ValueType properly set\n            dataType = dataType.FixupValueType();\n            dataSerializerType = dataSerializerType?.FixupValueType();\n\n            CecilSerializerContext.SerializableTypeInfo serializableTypeInfo;\n\n            if (dataSerializerType == null)\n            {\n                // TODO: We should avoid calling ResolveSerializer now just to have the dataSerializerType (we should do so only in a second step)\n                serializableTypeInfo = context.ResolveSerializer(dataType, profile: profile);\n                if (serializableTypeInfo == null)\n                    throw new InvalidOperationException(string.Format(\"Can't find serializer for type {0}\", dataType));\n                serializableTypeInfo.Local = local;\n                serializableTypeInfo.ExistingLocal = local;\n                dataSerializerType = serializableTypeInfo.SerializerType;\n            }","sourceCodeStart":54,"sourceCodeEnd":90,"githubUrl":"https://github.com/stride3d/stride/blob/96fad776d210c221682aac1ccdf4c79dc046fc38/sources/core/Stride.Core.AssemblyProcessor/Serializers/ReferencedAssemblySerializerProcessor.cs#L54-L90","documentation":"ProcessDataSerializerGlobalAttributes deduces which data type a [DataSerializer]-attributed serializer serves. When the serializer is generic (mode != None) and no data type was explicitly supplied, the type cannot be deduced, so this error is thrown.","triggerScenarios":"A DataSerializer subclass declares DataSerializerGenericMode (e.g. GenericArityAndArguments) but ProcessDataSerializerGlobalAttributes reaches it with dataType == null and cannot infer the target type from FindSerializerDataType.","commonSituations":"A generic serializer whose base DataSerializer<T> type cannot be resolved to a closed type; missing generic arguments on the serializer class; misconfigured [DataSerializer] usage.","solutions":["Ensure the generic serializer inherits a closed generic base like DataSerializer<List<T>> so the data type is inferable","Specify the data type explicitly via DataSerializer attribute on the target type instead of global attribute scanning","Remove the DataSerializerGenericMode if the serializer is actually non-generic","Fix the serializer class declaration so FindSerializerDataType can walk its base types"],"exampleFix":"// before\nclass MySerializer : DataSerializer<List<T>> { } // no generic mode param flow\n// after\n[DataSerializerGenericMode(DataSerializerGenericMode.GenericArityAndArguments)]\nclass MySerializer<T> : DataSerializer<List<T>> { }","handlingStrategy":"type-guard","validationCode":"static bool CanDeduceSerializerType(Type serializerType)\n{\n    var baseType = serializerType.BaseType;\n    while (baseType != null && !baseType.IsConstructedGenericType == false)\n    {\n        if (baseType.GetGenericTypeDefinition() == typeof(DataSerializer<>))\n            return !baseType.ContainsGenericParameters;\n        baseType = baseType.BaseType;\n    }\n    return false;\n}","typeGuard":"static bool IsGenericModeSerializer(Type t) =>\n    t.GetCustomAttribute<DataSerializerGenericModeAttribute>()?.Mode != DataSerializerGenericMode.None;","tryCatchPattern":"try { ProcessDataSerializer(serializerType); }\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"Can't deduce data serializer type\"))\n{\n    logger.Error($\"{serializerType} is generic but its data type cannot be deduced; close the generic base type\");\n}","preventionTips":["Generic serializers must derive from a closed DataSerializer<T> shape like DataSerializer<List<T>>","Set [DataSerializerGenericMode] on generic serializer classes","Avoid abstract open-generic intermediate base classes between serializer and DataSerializer<T>"],"tags":["serialization","generics","type-inference"],"backgroundTag":"type-mismatch","analyzedSha":"96fad776d210c221682aac1ccdf4c79dc046fc38","analyzedAt":"2026-09-14T02:59:31.279Z","contentChangedAt":"2026-09-14T02:59:31.279Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}