{"record":{"id":"6096fed92ec408fb","repo":"apache/dubbo","slug":"extension-type-type-is-not-an-interface","errorCode":null,"errorMessage":"Extension type (${type}) is not an interface!","messagePattern":"Extension type \\((.+?)\\) is not an interface!","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"dubbo-common/src/main/java/org/apache/dubbo/common/extension/ExtensionDirector.java","lineNumber":73,"sourceCode":"\n    public List<ExtensionPostProcessor> getExtensionPostProcessors() {\n        return extensionPostProcessors;\n    }\n\n    @Override\n    public ExtensionDirector getExtensionDirector() {\n        return this;\n    }\n\n    @Override\n    @SuppressWarnings(\"unchecked\")\n    public <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) {\n        checkDestroyed();\n        if (type == null) {\n            throw new IllegalArgumentException(\"Extension type == null\");\n        }\n        if (!type.isInterface()) {\n            throw new IllegalArgumentException(\"Extension type (\" + type + \") is not an interface!\");\n        }\n        if (!withExtensionAnnotation(type)) {\n            throw new IllegalArgumentException(\"Extension type (\" + type\n                    + \") is not an extension, because it is NOT annotated with @\" + SPI.class.getSimpleName() + \"!\");\n        }\n\n        // 1. find in local cache\n        ExtensionLoader<T> loader = (ExtensionLoader<T>) extensionLoadersMap.get(type);\n\n        ExtensionScope scope = extensionScopeMap.get(type);\n        if (scope == null) {\n            SPI annotation = type.getAnnotation(SPI.class);\n            scope = annotation.scope();\n            extensionScopeMap.put(type, scope);\n        }\n\n        if (loader == null && scope == ExtensionScope.SELF) {\n            // create an instance in self scope","sourceCodeStart":55,"sourceCodeEnd":91,"githubUrl":"https://github.com/apache/dubbo/blob/3a3043227f5571d25eb2889de5bca22f2914843b/dubbo-common/src/main/java/org/apache/dubbo/common/extension/ExtensionDirector.java#L55-L91","documentation":"Thrown by ExtensionDirector.getExtensionLoader(Class<T> type) when the type argument is a concrete class, enum, annotation, or primitive rather than a Java interface. Dubbo SPI mandates that extension points (the contract) must be interfaces; implementations are concrete classes discovered via configuration files. Passing a concrete class here confuses the contract/implementation distinction.","triggerScenarios":"Passing an implementation class instead of the SPI interface to getExtensionLoader(), e.g., getExtensionLoader(MyProtocolImpl.class) instead of getExtensionLoader(Protocol.class). Also triggered by passing a non-interface Class object obtained reflectively that happens to be a class or enum.","commonSituations":"Developer confuses the SPI extension point (interface) with the extension implementation (class) and passes the implementation. Copy-paste from example code that used a concrete class. A third-party integration library calls the Dubbo SPI API incorrectly.","solutions":["Replace the concrete class argument with the corresponding @SPI-annotated interface.","Inspect the intended extension point: find the interface annotated with @SPI that the concrete class implements.","Check the Dubbo documentation for the correct SPI interface name for the feature you are configuring."],"exampleFix":"// before — passing the implementation class\nExtensionLoader<MyProtocolImpl> loader =\n    director.getExtensionLoader(MyProtocolImpl.class);\n\n// after — pass the @SPI interface instead\nExtensionLoader<Protocol> loader =\n    director.getExtensionLoader(Protocol.class);","handlingStrategy":"validation","validationCode":"if (!type.isInterface()) {\n    throw new IllegalArgumentException(\n        type + \" is a concrete class — pass the @SPI interface, not an implementation\");\n}\nExtensionLoader<T> loader = director.getExtensionLoader(type);","typeGuard":"static <T> boolean isSpiInterface(Class<T> type) {\n    return type != null && type.isInterface();\n}","tryCatchPattern":"try {\n    ExtensionLoader<T> loader = director.getExtensionLoader(type);\n} catch (IllegalArgumentException e) {\n    if (e.getMessage().contains(\"is not an interface\")) {\n        log.error(\"Passed a concrete class to getExtensionLoader — use the SPI interface instead\", e);\n    }\n    throw e;\n}","preventionTips":["Always pass the @SPI-annotated interface class, never its implementation.","Document in your code which interface is the SPI contract vs which classes are implementations."],"tags":["dubbo-spi","type-validation","extension-system","configuration"],"backgroundTag":null,"analyzedSha":"3a3043227f5571d25eb2889de5bca22f2914843b","analyzedAt":"2026-08-14T00:43:19.853Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}