{"record":{"id":"008b866fa0978480","repo":"egametang/ET","slug":"config-factory-target-is-null-factory-gettype","errorCode":null,"errorMessage":"config factory target is null: {factory.GetType().FullName}","messagePattern":"config factory target is null: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"Packages/cn.etetet.loader/Scripts/Loader/Share/ConfigLoaderHelper.cs","lineNumber":15,"sourceCode":"using System;\nusing System.Collections.Generic;\nusing System.Reflection;\n\nnamespace ET\n{\n    public sealed class ConfigFactoryGroupCollection\n    {\n        private readonly Dictionary<Type, Dictionary<string, IConfigFactory>> factories = new();\n\n        public void Add(string configGroup, IConfigFactory factory)\n        {\n            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        }","sourceCodeStart":1,"sourceCodeEnd":33,"githubUrl":"https://github.com/egametang/ET/blob/5cab01f7a8bee5f49f4781eebe9e2b1c6d7ebe0f/Packages/cn.etetet.loader/Scripts/Loader/Share/ConfigLoaderHelper.cs#L1-L33","documentation":"Thrown by ConfigFactoryGroupCollection.Add when an IConfigFactory instance has a null ConfigType. ConfigType identifies which config category a factory builds; null means the factory was declared but never assigned a target Type, so it cannot be registered or looked up. This is a wiring/authoring defect in the factory class, surfaced at startup during CreateConfigFactories.","triggerScenarios":"A class implements IConfigFactory but its ConfigType property/field is left null (e.g. a partial config factory whose target was not set, or a factory generated by a codegen step that omitted the type). Hit during CreateConfigFactories which instantiates every IConfigFactory via reflection and calls Add.","commonSituations":"A new config factory was added but its ConfigType wasn't wired; a Luban/codegen run produced a factory stub without the target; a base-class factory whose ConfigType is meant to be set by a subclass but is instantiated directly.","solutions":["Open the named factory type and ensure its ConfigType returns a non-null Type (the config category it produces).","If the factory is abstract/base, mark it abstract so CreateConfigFactories's 'IsAbstract' filter (line 95) skips it.","Re-run the config codegen so the factory's ConfigType is populated."],"exampleFix":"// before\npublic class MyItemConfigFactory : IConfigFactory\n{\n    public Type ConfigType => null; // forgot to wire\n}\n\n// after\npublic class MyItemConfigFactory : IConfigFactory\n{\n    public Type ConfigType => typeof(ItemConfigCategory);\n}","handlingStrategy":"validation","validationCode":"// For factory authors — assert at construction\npublic Type ConfigType => _configType ?? throw new InvalidOperationException(nameof(ConfigType));","typeGuard":"static bool IsFactoryValid(IConfigFactory f) => f.ConfigType != null;","tryCatchPattern":null,"preventionTips":["Always wire ConfigType in factory classes; treat null as a compile-time error.","Mark base/abstract factories abstract so reflection skips them.","Add a unit test that instantiates every IConfigFactory and asserts ConfigType != null."],"tags":["loader","config","factory","reflection","codegen","startup"],"backgroundTag":null,"analyzedSha":"5cab01f7a8bee5f49f4781eebe9e2b1c6d7ebe0f","analyzedAt":"2026-08-13T21:10:40.377Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}