{"record":{"id":"40ba7ac024a7b959","repo":"apache/dubbo","slug":"spi-annotation-not-found-for-class-type-getname","errorCode":null,"errorMessage":"SPI annotation not found for class: ${type.getName()}","messagePattern":"SPI annotation not found for class: (.+?)","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"dubbo-common/src/main/java/org/apache/dubbo/rpc/model/ScopeModelUtil.java","lineNumber":34,"sourceCode":" */\npackage org.apache.dubbo.rpc.model;\n\nimport org.apache.dubbo.common.extension.ExtensionLoader;\nimport org.apache.dubbo.common.extension.SPI;\n\npublic class ScopeModelUtil {\n\n    public static <T> ScopeModel getOrDefault(ScopeModel scopeModel, Class<T> type) {\n        if (scopeModel != null) {\n            return scopeModel;\n        }\n        return getDefaultScopeModel(type);\n    }\n\n    private static <T> ScopeModel getDefaultScopeModel(Class<T> type) {\n        SPI spi = type.getAnnotation(SPI.class);\n        if (spi == null) {\n            throw new IllegalArgumentException(\"SPI annotation not found for class: \" + type.getName());\n        }\n        switch (spi.scope()) {\n            case FRAMEWORK:\n                return FrameworkModel.defaultModel();\n            case APPLICATION:\n                return ApplicationModel.defaultModel();\n            case MODULE:\n                return ApplicationModel.defaultModel().getDefaultModule();\n            default:\n                throw new IllegalStateException(\"Unable to get default scope model for type: \" + type.getName());\n        }\n    }\n\n    public static ModuleModel getModuleModel(ScopeModel scopeModel) {\n        if (scopeModel == null) {\n            return ApplicationModel.defaultModel().getDefaultModule();\n        }\n        if (scopeModel instanceof ModuleModel) {","sourceCodeStart":16,"sourceCodeEnd":52,"githubUrl":"https://github.com/apache/dubbo/blob/3a3043227f5571d25eb2889de5bca22f2914843b/dubbo-common/src/main/java/org/apache/dubbo/rpc/model/ScopeModelUtil.java#L16-L52","documentation":"ScopeModelUtil.getDefaultScopeModel() reads the @SPI annotation on the given type to determine which scope (FRAMEWORK/APPLICATION/MODULE) the default model should be. If the type is not annotated with @SPI, there is no scope metadata to read and Dubbo refuses to guess — the class is not a Dubbo extension point. The same check exists in getExtensionLoader() (error 372).","triggerScenarios":"Calling ScopeModelUtil.getOrDefault(null, SomeClass.class) or indirectly via a path that resolves the default scope model, where SomeClass is not annotated with @org.apache.dubbo.common.extension.SPI. Common when an internal helper resolves a default model for a plain interface or a class that should have been an SPI but isn't.","commonSituations":"Passing a non-extension interface (a plain business interface or a config class) where an SPI extension type is expected. Custom integrations that wrap Dubbo SPI resolution and forward arbitrary classes. Forgetting the @SPI annotation on a hand-written extension interface. Version mismatches where an interface lost its @SPI annotation.","solutions":["Pass an actual Dubbo SPI extension type — a class/interface annotated with @SPI (e.g. Protocol.class, Serialization.class).","If this is your own extension point, add `@SPI` (with a default value) to the interface.","Avoid calling ScopeModelUtil.getOrDefault with null scopeModel unless you are certain the type carries @SPI; instead pass an explicit ScopeModel.","Double-check the class import — make sure you are passing the Dubbo SPI interface, not its impl class or a config class."],"exampleFix":"// before (throws: HelloService has no @SPI)\nScopeModel sm = ScopeModelUtil.getOrDefault(null, HelloService.class);\n\n// after (pass an explicit scope, or a real @SPI type)\nScopeModel sm = ScopeModelUtil.getOrDefault(applicationModel, HelloService.class);\n// or, for an extension:\nScopeModel sm = ScopeModelUtil.getOrDefault(null, Protocol.class); // Protocol is @SPI","handlingStrategy":"validation","validationCode":"if (type.getAnnotation(SPI.class) == null) {\n    throw new IllegalArgumentException(\"Not an @SPI type: \" + type.getName()\n        + \" — pass a Dubbo extension interface or an explicit ScopeModel\");\n}\nScopeModel sm = ScopeModelUtil.getOrDefault(scopeModel, type);","typeGuard":"static boolean isSpiType(Class<?> type) {\n    return type != null && type.isInterface() && type.getAnnotation(SPI.class) != null;\n}","tryCatchPattern":null,"preventionTips":["Only pass @SPI-annotated interfaces to scope-default resolution.","When in doubt, pass an explicit ScopeModel so the SPI metadata is not consulted.","Annotate your own extension interfaces with @SPI."],"tags":["spi","scope-model","extension","annotation-missing"],"backgroundTag":null,"analyzedSha":"3a3043227f5571d25eb2889de5bca22f2914843b","analyzedAt":"2026-08-14T00:43:19.853Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}