apache/dubbo · error · IllegalArgumentException
Extension type (${type}) is not an extension, because it is
Error message
Extension type (${type}) is not an extension, because it is NOT annotated by @SPI! What it means
Thrown by ExtensionDirector.getExtensionLoader(Class<T> type) when the type IS an interface but is NOT annotated with @SPI. Dubbo's extension system only manages interfaces explicitly marked with @SPI — this annotation declares the extension point and optionally specifies a default implementation. Without it, Dubbo refuses to treat the interface as an extension point.
Source
Thrown at dubbo-common/src/main/java/org/apache/dubbo/common/extension/ExtensionDirector.java:76
}
@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 scope
loader = createExtensionLoader0(type);
}
View on GitHub (pinned to 3a3043227f)
Solutions
- Add the @SPI annotation to the interface: @SPI("defaultImplName") public interface MyExtension { ... }.
- Import org.apache.dubbo.common.extension.SPI to resolve the annotation.
- If using a third-party interface that you cannot annotate, wrap it in your own @SPI-annotated interface.
Example fix
// before — missing @SPI annotation
public interface MyLoadBalance {
<T> Invoker<T> select(List<Invoker<T>> invokers, URL url, Invocation invocation);
}
// after — annotate with @SPI
@SPI("random")
public interface MyLoadBalance {
<T> Invoker<T> select(List<Invoker<T>> invokers, URL url, Invocation invocation);
} Defensive patterns
Strategy: validation
Validate before calling
if (!type.isAnnotationPresent(SPI.class)) {
throw new IllegalArgumentException(
type + " must be annotated with @SPI to be used as a Dubbo extension point");
}
ExtensionLoader<T> loader = director.getExtensionLoader(type); Type guard
static <T> boolean hasSpiAnnotation(Class<T> type) {
return type != null && type.isInterface() && type.isAnnotationPresent(SPI.class);
} Try / catch
try {
ExtensionLoader<T> loader = director.getExtensionLoader(type);
} catch (IllegalArgumentException e) {
if (e.getMessage().contains("NOT annotated with @SPI")) {
log.error("Interface lacks @SPI annotation — add it to declare the extension point", e);
}
throw e;
} Prevention
- When creating a custom SPI extension point, always add @SPI("defaultName") on the interface.
- Ensure the SPI import (org.apache.dubbo.common.extension.SPI) survives IDE auto-import cleanup.
- Use a code template or Archetype for new SPI interfaces that includes the @SPI annotation.
When it happens
Trigger: Calling getExtensionLoader() with a plain Java interface that lacks the @SPI annotation. For example, passing a standard library interface (like java.lang.Runnable) or a custom interface you forgot to annotate. Also triggered when a custom interface was previously annotated but the annotation was removed during refactoring.
Common situations: Developer creates a custom SPI interface but forgets @SPI annotation. The @SPI annotation import was removed during IDE auto-import cleanup. Migrating from a framework where SPI registration works differently (e.g., Java ServiceLoader without annotations).
Related errors
- Extension type == null
- Extension type (${type}) is not an interface!
- Not find extension: ${name}
- Extension name == null
- Input type ${clazz} doesn't implement the Extension ${type}
AI-assisted analysis of apache/dubbo@3a3043227f (2026-08-14).
Data as JSON: /api/errors/fbeb66299df5d8bb.
Report an issue: GitHub.