apache/dubbo · error · IllegalStateException

Adaptive Extension already exists (Extension ${type})!

Error message

Adaptive Extension already exists (Extension ${type})!

What it means

Thrown by ExtensionLoader.addExtension(String name, Class<?> clazz) when the class is annotated @Adaptive but an adaptive class has already been registered or code-generated for this SPI type. Each extension point can have exactly one adaptive implementation — the one selected when no specific name is given at runtime. Attempting to register a second one is rejected.

Source

Thrown at dubbo-common/src/main/java/org/apache/dubbo/common/extension/ExtensionLoader.java:672

            throw new IllegalStateException("Input type " + clazz + " doesn't implement the Extension " + type);
        }
        if (clazz.isInterface()) {
            throw new IllegalStateException("Input type " + clazz + " can't be interface!");
        }

        if (!clazz.isAnnotationPresent(Adaptive.class)) {
            if (StringUtils.isBlank(name)) {
                throw new IllegalStateException("Extension name is blank (Extension " + type + ")!");
            }
            if (cachedClasses.get().containsKey(name)) {
                throw new IllegalStateException("Extension name " + name + " already exists (Extension " + type + ")!");
            }

            cachedNames.put(clazz, name);
            cachedClasses.get().put(name, clazz);
        } else {
            if (cachedAdaptiveClass != null) {
                throw new IllegalStateException("Adaptive Extension already exists (Extension " + type + ")!");
            }

            cachedAdaptiveClass = clazz;
        }
    }

    /**
     * Replace the existing extension via API
     *
     * @param name  extension name
     * @param clazz extension class
     * @throws IllegalStateException when extension to be placed doesn't exist
     * @deprecated not recommended any longer, and use only when test
     */
    @Deprecated
    public void replaceExtension(String name, Class<?> clazz) {
        checkDestroyed();
        getExtensionClasses(); // load classes

View on GitHub (pinned to 3a3043227f)

Solutions

  1. Use replaceExtension(name, clazz) if you need to swap the adaptive class at runtime.
  2. If you are in a test, destroy and recreate the ExtensionLoader/ScopeModel before registering a new adaptive class.
  3. Avoid providing a hand-written @Adaptive class when Dubbo already generates one — let code generation handle it.
  4. Remove @Adaptive from custom implementations unless you specifically need manual adaptive control.

Example fix

// before — adaptive class already exists
loader.addExtension("myAdaptive", MyAdaptiveClass.class); // @Adaptive on MyAdaptiveClass

// after — replace instead of add, or remove @Adaptive
loader.replaceExtension(null, MyAdaptiveClass.class); // replaces existing adaptive
// or: remove @Adaptive annotation from MyAdaptiveClass and register normally
Defensive patterns

Strategy: validation

Validate before calling

if (clazz.isAnnotationPresent(Adaptive.class)) {
    // check if adaptive class already exists
    try {
        loader.getAdaptiveExtension(); // will succeed if one exists
        // exists — use replaceExtension instead
        loader.replaceExtension(null, clazz);
    } catch (Exception e) {
        // does not exist yet — safe to add
        loader.addExtension(null, clazz);
    }
} else {
    loader.addExtension(name, clazz);
}

Prevention

When it happens

Trigger: Calling addExtension with an @Adaptive-annotated class when Dubbo already code-generated an adaptive class (the default behavior for SPI interfaces with @Adaptive methods) or when a previous addExtension already set the adaptive class.

Common situations: Dubbo auto-generates an adaptive class for SPI interfaces that have @Adaptive methods; calling addExtension with a hand-written @Adaptive class then conflicts. A test attempts to register a custom adaptive class without first clearing the existing one.

Related errors


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