{"record":{"id":"f701bae69bae9d3e","repo":"egametang/ET","slug":"config-interface-invalid-configtype-fullname","errorCode":null,"errorMessage":"config interface invalid: {configType.FullName}","messagePattern":"config interface invalid: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"Packages/cn.etetet.loader/Scripts/Loader/Share/ConfigLoaderHelper.cs","lineNumber":150,"sourceCode":"            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        {\n            ConfigGroupAttribute configGroupAttribute = factoryType.GetCustomAttribute<ConfigGroupAttribute>();\n            return string.IsNullOrWhiteSpace(configGroupAttribute?.Name) ? ConfigGroupNames.Config : configGroupAttribute.Name;\n        }\n\n        private static IConfigFactory GetConfigFactory(Type configType, ConfigFactoryGroupCollection configFactories)\n        {\n            if (!configFactories.TryGetFactories(configType, out Dictionary<string, IConfigFactory> groupFactories))\n            {\n                throw new Exception($\"config factory not found: {configType.FullName}\");\n            }","sourceCodeStart":132,"sourceCodeEnd":168,"githubUrl":"https://github.com/egametang/ET/blob/5cab01f7a8bee5f49f4781eebe9e2b1c6d7ebe0f/Packages/cn.etetet.loader/Scripts/Loader/Share/ConfigLoaderHelper.cs#L132-L168","documentation":"Thrown by LoadOneConfig when the created object is ASingleton but does not also implement IConfig. The load pipeline needs both: ASingleton for World registration and IConfig so ApplyLoadedConfigs can call ResolveRef (ConfigLoaderHelper.cs:59). Missing IConfig means cross-config reference resolution would skip this category.","triggerScenarios":"A config category derives from ASingleton but does not implement IConfig. This check runs only after the ASingleton check (217) passes, so the object IS a singleton but lacks the config interface.","commonSituations":"A category was made a singleton but the IConfig interface (with ResolveRef) was not implemented; an older base class provided ASingleton but a newer split dropped IConfig.","solutions":["Implement IConfig (including ResolveRef) on the named category.","Ensure the codegen template emits both the ASingleton base and the IConfig interface."],"exampleFix":"// before\npublic class MyConfigCategory : ASingleton { ... } // no IConfig\n\n// after\npublic class MyConfigCategory : ASingleton, IConfig\n{\n    public void ResolveRef() { /* bind cross-refs */ }\n}","handlingStrategy":"validation","validationCode":null,"typeGuard":"static bool ImplementsIConfig(Type t) => typeof(IConfig).IsAssignableFrom(t);","tryCatchPattern":null,"preventionTips":["Every config category must implement IConfig (including ResolveRef).","Keep the codegen template emitting both ASingleton and IConfig.","Add a build-time scan that fails if any config category lacks IConfig."],"tags":["loader","config","interface","iconfig","resolve-ref"],"backgroundTag":null,"analyzedSha":"5cab01f7a8bee5f49f4781eebe9e2b1c6d7ebe0f","analyzedAt":"2026-08-13T21:10:40.377Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}