{"record":{"id":"f6bd3525ba448851","repo":"egametang/ET","slug":"config-type-mismatch-expect-configtype-fullname","errorCode":null,"errorMessage":"config type mismatch: expect={configType.FullName} actual={category.GetType().FullName}","messagePattern":"config type mismatch: expect=(.+?) actual=(.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"Packages/cn.etetet.loader/Scripts/Loader/Share/ConfigLoaderHelper.cs","lineNumber":140,"sourceCode":"\n        public static ASingleton LoadOneConfig(Type configType, ConfigFactoryGroupCollection configFactories, Dictionary<Type, IConfig> loadedConfigs)\n        {\n            ConfigProcessAttribute configProcessAttribute = configType.GetCustomAttributes(typeof(ConfigProcessAttribute), false)[0] as ConfigProcessAttribute;\n            if (configProcessAttribute.ConfigType != ConfigType.Code)\n            {\n                throw new Exception($\"unsupported config type: {configProcessAttribute.ConfigType} {configType.FullName}\");\n            }\n\n            IConfigFactory factory = GetConfigFactory(configType, configFactories);\n            object category = factory.Create();\n            if (category == null)\n            {\n                throw new Exception($\"config create failed: {configType.FullName}\");\n            }\n\n            if (category.GetType() != configType)\n            {\n                throw new Exception($\"config type mismatch: expect={configType.FullName} actual={category.GetType().FullName}\");\n            }\n\n            if (category is not ASingleton singleton)\n            {\n                throw new Exception($\"config singleton invalid: {configType.FullName}\");\n            }\n\n            if (category is not IConfig iConfig)\n            {\n                throw new Exception($\"config interface invalid: {configType.FullName}\");\n            }\n\n            loadedConfigs.Add(configType, iConfig);\n            return singleton;\n        }\n\n        private static string GetConfigGroup(MemberInfo factoryType)\n        {","sourceCodeStart":122,"sourceCodeEnd":158,"githubUrl":"https://github.com/egametang/ET/blob/5cab01f7a8bee5f49f4781eebe9e2b1c6d7ebe0f/Packages/cn.etetet.loader/Scripts/Loader/Share/ConfigLoaderHelper.cs#L122-L158","documentation":"Thrown by LoadOneConfig when the object returned by factory.Create() has a runtime Type that does not exactly equal the requested configType. The loader keys configs by their declared category Type, so a mismatch means the factory produced the wrong category — a wiring/codegen defect rather than a data problem.","triggerScenarios":"GetConfigFactory resolved a factory whose ConfigType is X, but Create() returns an instance whose GetType() is Y != X. Happens when a factory's ConfigType and its Create() return type disagree (e.g. factory returns a base class or a sibling category).","commonSituations":"A factory's ConfigType was edited but Create() wasn't updated; a codegen template mismatch; a factory that returns a derived type where the exact-type check requires the declared category.","solutions":["Align the factory's ConfigType with the concrete type returned by Create() (they must be the same Type).","If inheritance is intended, relax the exact-equality check to IsAssignableFrom — but only if the design permits.","Re-run codegen so factory and category stay consistent."],"exampleFix":"// before — ConfigType and Create() return type differ\npublic Type ConfigType => typeof(BaseCategory);\npublic object Create() => new DerivedCategory(); // GetType() != BaseCategory\n\n// after — make them match\npublic Type ConfigType => typeof(DivedCategory);\npublic object Create() => new DerivedCategory();","handlingStrategy":"validation","validationCode":"// For factory authors: keep ConfigType and Create() return type identical\nDebug.Assert(typeof(MyCategory) == factory.ConfigType);","typeGuard":"static bool FactoryTypeConsistent(IConfigFactory f)\n{\n    object o = f.Create();\n    return o != null && o.GetType() == f.ConfigType;\n}","tryCatchPattern":null,"preventionTips":["Keep a factory's ConfigType and the concrete type returned by Create() in lockstep.","Regenerate factories whenever category types change.","Add a unit test asserting GetType()==ConfigType for every factory."],"tags":["loader","config","factory","type-mismatch","codegen"],"backgroundTag":null,"analyzedSha":"5cab01f7a8bee5f49f4781eebe9e2b1c6d7ebe0f","analyzedAt":"2026-08-13T21:10:40.377Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}