apache/dubbo · error · IllegalArgumentException
Extension type (${type}) is not an interface!
Error message
Extension type (${type}) is not an interface! What it means
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.
Source
Thrown at dubbo-common/src/main/java/org/apache/dubbo/common/extension/ExtensionDirector.java:73
public List<ExtensionPostProcessor> getExtensionPostProcessors() {
return extensionPostProcessors;
}
@Override
public ExtensionDirector getExtensionDirector() {
return this;
}
@Override
@SuppressWarnings("unchecked")
public <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) {
checkDestroyed();
if (type == null) {
throw new IllegalArgumentException("Extension type == null");
}
if (!type.isInterface()) {
throw new IllegalArgumentException("Extension type (" + type + ") is not an interface!");
}
if (!withExtensionAnnotation(type)) {
throw new IllegalArgumentException("Extension type (" + type
+ ") is not an extension, because it is NOT annotated with @" + SPI.class.getSimpleName() + "!");
}
// 1. find in local cache
ExtensionLoader<T> loader = (ExtensionLoader<T>) extensionLoadersMap.get(type);
ExtensionScope scope = extensionScopeMap.get(type);
if (scope == null) {
SPI annotation = type.getAnnotation(SPI.class);
scope = annotation.scope();
extensionScopeMap.put(type, scope);
}
if (loader == null && scope == ExtensionScope.SELF) {
// create an instance in self scopeView on GitHub (pinned to 3a3043227f)
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.
Example fix
// before — passing the implementation class
ExtensionLoader<MyProtocolImpl> loader =
director.getExtensionLoader(MyProtocolImpl.class);
// after — pass the @SPI interface instead
ExtensionLoader<Protocol> loader =
director.getExtensionLoader(Protocol.class); Defensive patterns
Strategy: validation
Validate before calling
if (!type.isInterface()) {
throw new IllegalArgumentException(
type + " is a concrete class — pass the @SPI interface, not an implementation");
}
ExtensionLoader<T> loader = director.getExtensionLoader(type); Type guard
static <T> boolean isSpiInterface(Class<T> type) {
return type != null && type.isInterface();
} Try / catch
try {
ExtensionLoader<T> loader = director.getExtensionLoader(type);
} catch (IllegalArgumentException e) {
if (e.getMessage().contains("is not an interface")) {
log.error("Passed a concrete class to getExtensionLoader — use the SPI interface instead", e);
}
throw e;
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Extension type == null
- Extension type (${type}) is not an extension, because it is
- Not find extension: ${name}
- Input type ${clazz} doesn't implement the Extension ${type}
- Input type ${clazz} can't be interface!
AI-assisted analysis of apache/dubbo@3a3043227f (2026-08-14).
Data as JSON: /api/errors/6096fed92ec408fb.
Report an issue: GitHub.