apache/dubbo · error · IllegalStateException

The local implementation class <localClass.getName()> not im

Error message

The local implementation class <localClass.getName()> not implement interface <interfaceClass.getName()>

What it means

Thrown by AbstractInterfaceConfig.verify during stub/local validation (verifyStubAndLocal): the configured local/stub implementation class does not implement the service interface (interfaceClass.isAssignableFrom(localClass) is false). Dubbo requires the stub/local class to be an implementation of the interface so it can substitute for the real service on the client side.

Source

Thrown at dubbo-common/src/main/java/org/apache/dubbo/config/AbstractInterfaceConfig.java:485

     *                       side, it is the {@link Class} of the remote service interface
     */
    protected void checkStubAndLocal(Class<?> interfaceClass) {
        verifyStubAndLocal(local, "Local", interfaceClass);
        verifyStubAndLocal(stub, "Stub", interfaceClass);
    }

    private void verifyStubAndLocal(String className, String label, Class<?> interfaceClass) {
        if (ConfigUtils.isNotEmpty(className)) {
            Class<?> localClass = ConfigUtils.isDefault(className)
                    ? ReflectUtils.forName(interfaceClass.getName() + label)
                    : ReflectUtils.forName(className);
            verify(interfaceClass, localClass);
        }
    }

    private void verify(Class<?> interfaceClass, Class<?> localClass) {
        if (!interfaceClass.isAssignableFrom(localClass)) {
            throw new IllegalStateException("The local implementation class " + localClass.getName()
                    + " not implement interface " + interfaceClass.getName());
        }

        try {
            // Check if the localClass a constructor with parameter whose type is interfaceClass
            ReflectUtils.findConstructor(localClass, interfaceClass);
        } catch (NoSuchMethodException e) {
            throw new IllegalStateException("No such constructor \"public " + localClass.getSimpleName() + "("
                    + interfaceClass.getName() + ")\" in local implementation class " + localClass.getName());
        }
    }

    private void convertRegistryIdsToRegistries() {
        computeValidRegistryIds();
        if (StringUtils.isEmpty(registryIds)) {
            if (CollectionUtils.isEmpty(registries)) {
                List<RegistryConfig> registryConfigs = getConfigManager().getDefaultRegistries();
                registryConfigs = new ArrayList<>(registryConfigs);

View on GitHub (pinned to 3a3043227f)

Solutions

  1. Make the stub/local class implement the exact service interface (implements com.acme.Greeting).
  2. If using default naming (local=true), create a class named <InterfaceName>Local that implements the interface.
  3. Point the stub/local attribute to the correct implementing class.
  4. Remove the local/stub configuration if no client-side stub is needed.

Example fix

// before
public class GreetingLocal {} // does not implement Greeting
<dubbo:service interface="com.acme.Greeting" local="true"/>
// after
public class GreetingLocal implements Greeting {
    public GreetingLocal() {}
    // ... implement methods
}
<dubbo:service interface="com.acme.Greeting" local="true"/>
Defensive patterns

Strategy: validation

Validate before calling

void assertStubImplements(Class<?> iface, String stubClassName) throws ClassNotFoundException {
    Class<?> stub = Class.forName(stubClassName);
    if (!iface.isAssignableFrom(stub))
        throw new IllegalStateException(stub + " must implement " + iface.getName());
}

Type guard

boolean implementsInterface(Class<?> candidate, Class<?> iface) {
    return candidate != null && iface.isAssignableFrom(candidate);
}

Try / catch

try {
    serviceConfig.export(); // or reference
} catch (IllegalStateException e) {
    if (e.getMessage().startsWith("The local implementation class") && e.getMessage().contains("not implement interface")) {
        // make the stub/local class implement the interface
    }
    throw e;
}

Prevention

When it happens

Trigger: checkStubAndLocal loads the class named by the 'local' or 'stub' attribute (either a custom class or interfaceName+'Local'/'Stub') and checks it implements the interface. If it doesn't, this is thrown. Triggered at export (provider local) or reference (consumer stub) startup.

Common situations: The stub/local class implements a different interface or none. A copy-paste pointed stub to the wrong class. The interface name was changed but the stub class wasn't updated. 'local=true'/'stub=true' (default) made Dubbo look for interfaceName+'Local'/'Stub' which doesn't exist or implements the wrong interface.

Related errors


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