{"record":{"id":"4151a84da62ba525","repo":"egametang/ET","slug":"duplicate-config-factory-factory-configtype-full","errorCode":null,"errorMessage":"duplicate config factory: {factory.ConfigType.FullName} group={configGroup}","messagePattern":"duplicate config factory: (.+?) group=(.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"Packages/cn.etetet.loader/Scripts/Loader/Share/ConfigLoaderHelper.cs","lineNumber":31,"sourceCode":"            if (factory.ConfigType == null)\n            {\n                throw new Exception($\"config factory target is null: {factory.GetType().FullName}\");\n            }\n\n            if (string.IsNullOrWhiteSpace(configGroup))\n            {\n                throw new Exception($\"config group is empty: {factory.GetType().FullName}\");\n            }\n\n            if (!this.factories.TryGetValue(factory.ConfigType, out Dictionary<string, IConfigFactory> groupFactories))\n            {\n                groupFactories = new Dictionary<string, IConfigFactory>(StringComparer.Ordinal);\n                this.factories.Add(factory.ConfigType, groupFactories);\n            }\n\n            if (!groupFactories.TryAdd(configGroup, factory))\n            {\n                throw new Exception($\"duplicate config factory: {factory.ConfigType.FullName} group={configGroup}\");\n            }\n        }\n\n        public bool TryGetFactories(Type configType, out Dictionary<string, IConfigFactory> groupFactories)\n        {\n            return this.factories.TryGetValue(configType, out groupFactories);\n        }\n    }\n\n    internal static class ConfigLoaderHelper\n    {\n        public static List<Type> GetConfigTypes()\n        {\n            List<Type> configTypes = new(CodeTypes.Instance.GetTypes(typeof(ConfigProcessAttribute)));\n            configTypes.Sort((left, right) => string.CompareOrdinal(left.FullName, right.FullName));\n            return configTypes;\n        }\n","sourceCodeStart":13,"sourceCodeEnd":49,"githubUrl":"https://github.com/egametang/ET/blob/5cab01f7a8bee5f49f4781eebe9e2b1c6d7ebe0f/Packages/cn.etetet.loader/Scripts/Loader/Share/ConfigLoaderHelper.cs#L13-L49","documentation":"Thrown by ConfigFactoryGroupCollection.Add when TryAdd(configGroup, factory) fails — i.e. a factory for the SAME (ConfigType, configGroup) pair was already registered. The collection keys factories by ConfigType then by group name, so a duplicate means two factories compete to produce the same config category under the same group.","triggerScenarios":"Two IConfigFactory classes both return the same ConfigType and the same ConfigGroup attribute/default. CreateConfigFactories iterates all factory types sorted by FullName and Add's each; the second registration of an identical (type, group) pair throws.","commonSituations":"A factory was copy-pasted without changing its target ConfigType; a codegen run emitted a duplicate; an old factory wasn't removed after adding a new one for the same category.","solutions":["Search for all factories whose ConfigType matches the one in the message and ensure only one exists per group.","If multiple variants are intended, give each a distinct ConfigGroup name.","Remove or rename the duplicate factory class."],"exampleFix":"// before — two factories, both ConfigType=ItemConfigCategory, both default group\npublic class ItemConfigFactoryA : IConfigFactory { public Type ConfigType => typeof(ItemConfigCategory); }\npublic class ItemConfigFactoryB : IConfigFactory { public Type ConfigType => typeof(ItemConfigCategory); }\n\n// after — only one, or distinct groups\npublic class ItemConfigFactory : IConfigFactory { public Type ConfigType => typeof(ItemConfigCategory); }","handlingStrategy":"validation","validationCode":"// Before adding, check for an existing registration\nif (groupFactories != null && groupFactories.ContainsKey(configGroup))\n{ Log.Error($\"duplicate factory for {factory.ConfigType} group={configGroup}\"); return; }","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Grep for all factories with the same ConfigType; keep exactly one per group.","Use distinct ConfigGroup names when multiple variants are intentional.","Add a startup test that fails on duplicate registrations."],"tags":["loader","config","factory","duplicate","registration"],"backgroundTag":null,"analyzedSha":"5cab01f7a8bee5f49f4781eebe9e2b1c6d7ebe0f","analyzedAt":"2026-08-13T21:10:40.377Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}