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 scope

View on GitHub (pinned to 3a3043227f)

Solutions

  1. Replace the concrete class argument with the corresponding @SPI-annotated interface.
  2. Inspect the intended extension point: find the interface annotated with @SPI that the concrete class implements.
  3. 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

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


AI-assisted analysis of apache/dubbo@3a3043227f (2026-08-14). Data as JSON: /api/errors/6096fed92ec408fb. Report an issue: GitHub.