apache/dubbo · error · IllegalStateException
More than 1 adaptive class found: {}, {}
Error message
More than 1 adaptive class found: {}, {} What it means
Thrown by cacheAdaptiveClass() when a second, different class annotated with @Adaptive is encountered for the same SPI interface while loading SPI configs. Dubbo permits at most one @Adaptive-annotated implementation per SPI interface; if two distinct classes claim @Adaptive, the second registration (without overridden=true) fails. The first cached adaptive class wins.
Source
Thrown at dubbo-common/src/main/java/org/apache/dubbo/common/extension/ExtensionLoader.java:1388
if (activate != null) {
cachedActivates.put(name, activate);
} else if (Dubbo2CompactUtils.isEnabled() && Dubbo2ActivateUtils.isActivateLoaded()) {
// support com.alibaba.dubbo.common.extension.Activate
Annotation oldActivate = clazz.getAnnotation(Dubbo2ActivateUtils.getActivateClass());
if (oldActivate != null) {
cachedActivates.put(name, oldActivate);
}
}
}
/**
* cache Adaptive class which is annotated with <code>Adaptive</code>
*/
private void cacheAdaptiveClass(Class<?> clazz, boolean overridden) {
if (cachedAdaptiveClass == null || overridden) {
cachedAdaptiveClass = clazz;
} else if (!cachedAdaptiveClass.equals(clazz)) {
throw new IllegalStateException(
"More than 1 adaptive class found: " + cachedAdaptiveClass.getName() + ", " + clazz.getName());
}
}
/**
* cache wrapper class
* <p>
* like: ProtocolFilterWrapper, ProtocolListenerWrapper
*/
private void cacheWrapperClass(Class<?> clazz) {
if (cachedWrapperClasses == null) {
cachedWrapperClasses = new ConcurrentHashSet<>();
}
cachedWrapperClasses.add(clazz);
}
/**
* test if clazz is a wrapper classView on GitHub (pinned to 3a3043227f)
Solutions
- Ensure only one class annotated with @Adaptive implements the SPI interface across the entire classpath.
- If overriding the built-in adaptive class, exclude the original jar/config or use the overridden loading path so the later one replaces the earlier.
- Run 'grep -r @Adaptive' across your dependencies or use jar scanning to find both adaptive classes and remove the unintended one.
Example fix
// before: two classes
// jar1: @Adaptive public class AProtocol implements Protocol {}
// jar2: @Adaptive public class BProtocol implements Protocol {}
// throws [149]
// after: keep only one, remove @Adaptive from the other or delete the class
// jar1: @Adaptive public class AProtocol implements Protocol {} Defensive patterns
Strategy: validation
Validate before calling
// Scan classpath for multiple @Adaptive classes on the same interface
int count = 0;
for (Class<?> c : scanImplementations(iface)) {
if (c.isAnnotationPresent(Adaptive.class)) count++;
}
if (count > 1) throw new IllegalStateException("Multiple @Adaptive for " + iface); Prevention
- Ensure at most one @Adaptive-annotated implementation exists per SPI interface on the classpath.
- When overriding the built-in adaptive class, exclude the original artifact or use the overridden loading strategy.
- Scan dependencies for stray @Adaptive classes during integration testing.
When it happens
Trigger: Two jars each ship a class annotated with @Adaptive implementing the same SPI interface. loadClass() routes @Adaptive-annotated classes to cacheAdaptiveClass(), and if cachedAdaptiveClass is already set to a different class, the guard throws. Common with custom overrides that forget to remove the original adaptive class.
Common situations: A custom jar provides its own @Adaptive implementation of an interface that already has a built-in adaptive class (e.g., dubbo's own Protocol$Adaptive-style annotated class); merging modules that each define an adaptive implementation; a shading/relocation that duplicates the adaptive class.
Related errors
- Duplicate extension {} name {} on {} and {}
- Can't create adaptive extension {}, cause: {}
- Extension name ${name} already exists (Extension ${type})!
- Adaptive Extension already exists (Extension ${type})!
- Extension instance (name: {}, class: {}) couldn't be instant
AI-assisted analysis of apache/dubbo@3a3043227f (2026-08-14).
Data as JSON: /api/errors/14247870501ed199.
Report an issue: GitHub.