{"record":{"id":"6c0cbd357cad115e","repo":"stride3d/stride","slug":"two-different-classes-have-the-same-datacontract-alias","errorCode":null,"errorMessage":"Two different classes have the same DataContract Alias [${dataContractAliasEntry.Name}]: ${dataContractAliasEntry.Type} and ${DataContractAliasMapping[dataContractAliasEntry.Name]}","messagePattern":"Two different classes have the same DataContract Alias \\[(.+?)\\]: (.+?) and (.+?)","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"sources/core/Stride.Core/Serialization/DataSerializerFactory.cs","lineNumber":243,"sourceCode":"        {\n            AvailableAssemblySerializers.TryGetValue(assembly, out var assemblySerializers);\n            return assemblySerializers;\n        }\n    }\n\n    private static void RegisterSerializers(AssemblySerializers assemblySerializers)\n    {\n        // Register data contract aliases\n        foreach (var dataContractAliasEntry in assemblySerializers.DataContractAliases)\n        {\n            try\n            {\n                // TODO: Warning, exception or override if collision? (currently exception)\n                DataContractAliasMapping.Add(dataContractAliasEntry.Name, dataContractAliasEntry.Type);\n            }\n            catch (Exception)\n            {\n                throw new InvalidOperationException($\"Two different classes have the same DataContract Alias [{dataContractAliasEntry.Name}]: {dataContractAliasEntry.Type} and {DataContractAliasMapping[dataContractAliasEntry.Name]}\");\n            }\n        }\n\n        // Register serializers\n        foreach (var assemblySerializerPerProfile in assemblySerializers.Profiles)\n        {\n            var profile = assemblySerializerPerProfile.Key;\n\n            if (!DataSerializersPerProfile.TryGetValue(profile, out var dataSerializers))\n            {\n                dataSerializers = new Dictionary<Type, AssemblySerializerEntry>();\n                DataSerializersPerProfile.Add(profile, dataSerializers);\n            }\n\n            foreach (var assemblySerializer in assemblySerializerPerProfile.Value)\n            {\n                dataSerializers.TryAdd(assemblySerializer.ObjectType, assemblySerializer);\n            }","sourceCodeStart":225,"sourceCodeEnd":261,"githubUrl":"https://github.com/stride3d/stride/blob/96fad776d210c221682aac1ccdf4c79dc046fc38/sources/core/Stride.Core/Serialization/DataSerializerFactory.cs#L225-L261","documentation":"DataSerializerFactory scans assemblies for [DataContract] types and builds a mapping from each DataContract Alias to its Type. Two different classes declared the same alias, so the mapping would be ambiguous; the factory throws InvalidOperationException instead of silently letting the last-registered type win.","triggerScenarios":"Registering two assemblies (RegisterSerializers, via RegisterSerializationAssembly/UnregisterSerializationAssembly) that each contain a [DataContract(\"SameAlias\")] on different types; adding a DataContract alias that duplicates one in a referenced module; stale serializer assembly generated from an older alias still being loaded.","commonSituations":"Renaming a class but leaving its old DataContract alias in place while a new class takes the same alias; two plugins shipping identically-named custom data-contract types; copy-pasting a component class (including its DataContract attribute) into another assembly without changing the alias; assembly regeneration/registration ordering after a version upgrade.","solutions":["Make each [DataContract(\"Alias\")] alias unique across all registered assemblies","If the duplicate is stale, delete or rename the old attribute before re-registering the assembly","Regenerate the serializer assembly (Stride codegen) after fixing aliases, then re-run RegisterSerializationAssembly","If a collision is intentional (same type moved assemblies), keep only one registration or unregister the old assembly first"],"exampleFix":"// before\n// AssemblyA: [DataContract(\"MyData\")] class MyData { }\n// AssemblyB: [DataContract(\"MyData\")] class MyDataVariant { }\n// after\n// AssemblyB: [DataContract(\"MyDataVariant\")] class MyDataVariant { }","handlingStrategy":"validation","validationCode":"// scan registered assemblies for duplicate DataContract aliases before registering\nvar aliasGroups = assemblies\n    .SelectMany(a => a.GetTypes().Where(t => t.GetCustomAttributes<DataContractAliasAttribute>().Any()))\n    .SelectMany(t => t.GetCustomAttributes<DataContractAliasAttribute>().Select(attr => (attr.Name, Type: t)));\nvar dupes = aliasGroups.GroupBy(x => x.Name).Where(g => g.Select(x => x.Type).Distinct().Count() > 1).ToList();\nif (dupes.Any()) throw new InvalidOperationException(\"Duplicate aliases: \" + string.Join(\",\", dupes.Select(d => d.Key)));","typeGuard":null,"tryCatchPattern":"try\n{\n    Serialization.RegisterSerializationAssembly(assembly);\n}\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"DataContract Alias\"))\n{\n    logger.Fatal(ex, \"DataContract alias collision - fix the [DataContract] aliases listed above\");\n    throw;\n}","preventionTips":["Keep DataContract aliases globally unique; prefix them with your module name","After renaming a class, update its alias rather than leaving a stale duplicate","Regenerate serializer assemblies after any DataContract attribute change","Only register each assembly once (unregister before re-registering)"],"tags":["serialization","datacontract","alias-collision","stride"],"backgroundTag":"duplicate-datacontract-alias","analyzedSha":"96fad776d210c221682aac1ccdf4c79dc046fc38","analyzedAt":"2026-09-14T02:59:31.279Z","contentChangedAt":"2026-09-14T02:59:31.279Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}