{"record":{"id":"38efaa2bea2f2c99","repo":"alibaba/canal","slug":"extension-type-is-not-interface-38efaa","errorCode":null,"errorMessage":"Extension type({}) is not interface!","messagePattern":"Extension type\\((.+?)\\) is not interface!","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"connector/core/src/main/java/com/alibaba/otter/canal/connector/core/spi/ExtensionLoader.java","lineNumber":74,"sourceCode":"    private final ConcurrentMap<String, Holder<Object>>              cachedInstances            = new ConcurrentHashMap<>();\n\n    private String                                                   cachedDefaultName;\n\n    private ConcurrentHashMap<String, IllegalStateException>         exceptions                 = new ConcurrentHashMap<>();\n\n    private static <T> boolean withExtensionAnnotation(Class<T> type) {\n        return type.isAnnotationPresent(SPI.class);\n    }\n\n    public static <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) {\n        return getExtensionLoader(type, DEFAULT_CLASSLOADER_POLICY);\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public static <T> ExtensionLoader<T> getExtensionLoader(Class<T> type, String classLoaderPolicy) {\n        if (type == null) throw new IllegalArgumentException(\"Extension type == null\");\n        if (!type.isInterface()) {\n            throw new IllegalArgumentException(\"Extension type(\" + type + \") is not interface!\");\n        }\n        if (!withExtensionAnnotation(type)) {\n            throw new IllegalArgumentException(\"Extension type(\" + type + \") is not extension, because WITHOUT @\"\n                                               + SPI.class.getSimpleName() + \" Annotation!\");\n        }\n\n        ExtensionLoader<T> loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);\n        if (loader == null) {\n            EXTENSION_LOADERS.putIfAbsent(type, new ExtensionLoader<T>(type, classLoaderPolicy));\n            loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);\n        }\n        return loader;\n    }\n\n    public ExtensionLoader(Class<?> type){\n        this.type = type;\n        this.classLoaderPolicy = DEFAULT_CLASSLOADER_POLICY;\n    }","sourceCodeStart":56,"sourceCodeEnd":92,"githubUrl":"https://github.com/alibaba/canal/blob/87be50e87686a3e8af08c368d0e1ffd1f59eb04a/connector/core/src/main/java/com/alibaba/otter/canal/connector/core/spi/ExtensionLoader.java#L56-L92","documentation":"Thrown by ExtensionLoader.getExtensionLoader when the supplied type is not a Java interface. Canal's SPI mechanism (Dubbo-style) only loads extensions for interfaces; passing a concrete class or enum is rejected because the whole point of SPI is to bind implementations to an abstraction.","triggerScenarios":"Calling getExtensionLoader(SomeImpl.class) where SomeImpl is a class rather than an interface; passing an enum or annotation type.","commonSituations":"Developer mistakenly passes the implementation class instead of the extension interface; refactor renamed the interface and the call site was not updated.","solutions":["Pass the extension interface (the one annotated @SPI), not an implementation class.","Verify the class literal in the getExtensionLoader call is an interface via reflection if unsure."],"exampleFix":"// before\nExtensionLoader.getExtensionLoader(RocketMQProducer.class);  // impl\n// after\nExtensionLoader.getExtensionLoader(CanalMQProducer.class);    // @SPI interface","handlingStrategy":"validation","validationCode":"// Guard: require an interface\nif (type == null || !type.isInterface()) {\n    throw new IllegalArgumentException(type + \" is not an extension interface\");\n}","typeGuard":"boolean isSpiInterface(Class<?> type) {\n    return type != null && type.isInterface()\n        && type.isAnnotationPresent(\n            com.alibaba.otter.canal.connector.core.spi.SPI.class);\n}","tryCatchPattern":null,"preventionTips":["Always pass the @SPI-annotated interface, never an implementation class.","Unit-test SPI acquisition against the interface type."],"tags":["spi","programming-error","extension-loader"],"backgroundTag":null,"analyzedSha":"87be50e87686a3e8af08c368d0e1ffd1f59eb04a","analyzedAt":"2026-08-14T04:30:11.918Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}