apache/dubbo · error · UnsupportedOperationException

The method %s of interface %s is not adaptive method!

Error message

The method %s of interface %s is not adaptive method!

What it means

This is a generated-code template (CODE_UNSUPPORTED) emitted by AdaptiveClassCodeGenerator for methods on an SPI interface that are NOT annotated with @Adaptive. At runtime, the generated $Adaptive class throws UnsupportedOperationException when such a method is invoked. It signals that the called method is not adaptive and therefore the adaptive instance cannot route it to a concrete extension.

Source

Thrown at dubbo-common/src/main/java/org/apache/dubbo/common/extension/AdaptiveClassCodeGenerator.java:58

    private static final Logger logger = LoggerFactory.getLogger(AdaptiveClassCodeGenerator.class);

    private static final String CLASS_NAME_INVOCATION = "org.apache.dubbo.rpc.Invocation";

    private static final String CODE_PACKAGE = "package %s;\n";

    private static final String CODE_IMPORTS = "import %s;\n";

    private static final String CODE_CLASS_DECLARATION = "public class %s$Adaptive implements %s {\n";

    private static final String CODE_METHOD_DECLARATION = "public %s %s(%s) %s {\n%s}\n";

    private static final String CODE_METHOD_ARGUMENT = "%s arg%d";

    private static final String CODE_METHOD_THROWS = "throws %s";

    private static final String CODE_UNSUPPORTED =
            "throw new UnsupportedOperationException(\"The method %s of interface %s is not adaptive method!\");\n";

    private static final String CODE_URL_NULL_CHECK =
            "if (arg%d == null) throw new IllegalArgumentException(\"url == null\");\n%s url = arg%d;\n";

    private static final String CODE_EXT_NAME_ASSIGNMENT = "String extName = %s;\n";

    private static final String CODE_EXT_NAME_NULL_CHECK = "if(extName == null) "
            + "throw new IllegalStateException(\"Failed to get extension (%s) name from url (\" + url.toString() + \") use keys(%s)\");\n";

    private static final String CODE_INVOCATION_ARGUMENT_NULL_CHECK =
            "if (arg%d == null) throw new IllegalArgumentException(\"invocation == null\"); "
                    + "String methodName = arg%d.getMethodName();\n";

    private static final String CODE_SCOPE_MODEL_ASSIGNMENT =
            "ScopeModel scopeModel = ScopeModelUtil.getOrDefault(url.getScopeModel(), %s.class);\n";
    private static final String CODE_EXTENSION_ASSIGNMENT =
            "%s extension = (%<s)scopeModel.getExtensionLoader(%s.class).getExtension(extName);\n";

View on GitHub (pinned to 3a3043227f)

Solutions

  1. Check which method is being called and whether it is annotated @Adaptive on the SPI interface.
  2. Obtain the concrete extension instance by name instead of the adaptive instance: extensionLoader.getExtension(name) rather than getAdaptiveExtension().
  3. If you are the SPI author and the method should be adaptive, annotate it with @Adaptive.

Example fix

// before
Protocol adaptive = extensionLoader.getAdaptiveExtension();
adaptive.someNonAdaptiveMethod(url); // throws

// after
Protocol concrete = extensionLoader.getExtension("dubbo");
concrete.someNonAdaptiveMethod(url);
Defensive patterns

Strategy: validation

Validate before calling

boolean isAdaptive = Arrays.stream(type.getMethods())
    .anyMatch(m -> m.isAnnotationPresent(Adaptive.class));
if (!isAdaptive) {
    // cannot use adaptive instance for this method
}

Type guard

static boolean isAdaptiveMethod(Class<?> spiType, String methodName, Class<?>... paramTypes) {
    try {
        Method m = spiType.getMethod(methodName, paramTypes);
        return m.isAnnotationPresent(Adaptive.class);
    } catch (NoSuchMethodException e) {
        return false;
    }
}

Try / catch

try {
    adaptiveExt.someMethod(url);
} catch (UnsupportedOperationException e) {
    if (e.getMessage().contains("not adaptive method")) {
        // obtain a named extension instead
        ext = loader.getExtension("default");
    } else throw e;
}

Prevention

When it happens

Trigger: At runtime, calling a non-@Adaptive method on an adaptive extension instance obtained via ExtensionLoader.getAdaptiveExtension(). The generated code unconditionally throws for any method lacking the @Adaptive annotation.

Common situations: Calling an SPI interface method that was not marked @Adaptive on the adaptive proxy. For example, Protocol has some methods annotated @Adaptive and some not; calling a non-adaptive method through the adaptive instance. Happens when framework code or user code obtains the wrong type of extension instance.

Related errors


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