apache/dubbo · error · IllegalStateException

No such constructor "public <localClass.getSimpleName()>(<in

Error message

No such constructor "public <localClass.getSimpleName()>(<interfaceClass.getName()>)" in local implementation class <localClass.getName()>

What it means

Thrown by AbstractInterfaceConfig.verify() when a local implementation class (set via the local/stub attribute) does not expose a public constructor that takes the service interface as its sole parameter. Dubbo's local stub mechanism requires this constructor so the framework can instantiate the stub and inject a reference to the remote interface for client-side logic execution. The verify() method first confirms the local class implements the interface, then uses ReflectUtils.findConstructor() to locate the required constructor signature, throwing IllegalStateException if it cannot.

Source

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

        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);
                setRegistries(registryConfigs);
            }
        } else {
            String[] ids = COMMA_SPLIT_PATTERN.split(registryIds);
            List<RegistryConfig> tmpRegistries = new ArrayList<>();
            Arrays.stream(ids).forEach(id -> {
                if (tmpRegistries.stream().noneMatch(reg -> reg.getId().equals(id))) {
                    Optional<RegistryConfig> globalRegistry = getConfigManager().getRegistry(id);

View on GitHub (pinned to 3a3043227f)

Solutions

  1. Add a public constructor to the local implementation class whose single parameter is the service interface type, e.g. `public MyLocalImpl(MyService service) { ... }`.
  2. Verify the local class actually implements the declared interface (the preceding isAssignableFrom check must also pass).
  3. Ensure the constructor is public and not generic/erased in a way that prevents reflective lookup.

Example fix

// before
public class MyLocalImpl implements MyService {
    public MyLocalImpl() { }
}
// after
public class MyLocalImpl implements MyService {
    private final MyService remote;
    public MyLocalImpl(MyService remote) { this.remote = remote; }
}
Defensive patterns

Strategy: validation

Validate before calling

// Before setting local/stub, verify the constructor exists
import org.apache.dubbo.common.utils.ReflectUtils;

Class<?> iface = MyService.class;
Class<?> local = MyLocalImpl.class;
if (!iface.isAssignableFrom(local)) {
    throw new IllegalStateException("local class does not implement interface");
}
try {
    ReflectUtils.findConstructor(local, iface);
} catch (NoSuchMethodException e) {
    throw new IllegalStateException("Missing public constructor " + local.getSimpleName() + "(" + iface.getName() + ")", e);
}
serviceConfig.setLocal(local.getName());

Type guard

static boolean hasDubboStubConstructor(Class<?> iface, Class<?> local) {
    if (!iface.isAssignableFrom(local)) return false;
    try {
        org.apache.dubbo.common.utils.ReflectUtils.findConstructor(local, iface);
        return true;
    } catch (NoSuchMethodException e) {
        return false;
    }
}

Try / catch

try {
    serviceConfig.setLocal(MyLocalImpl.class.getName());
    serviceConfig.export();
} catch (IllegalStateException e) {
    if (e.getMessage().contains("No such constructor")) {
        // add the required public Constructor(iface) to the stub class
    } else throw e;
}

Prevention

When it happens

Trigger: Calling ServiceConfig.setLocal() or configuring <dubbo:service local="..."> / stub="..." with a class that lacks a `public LocalClass(InterfaceType)` constructor. Also triggered by the local stub SPI when the stub class only has a default no-arg constructor or a constructor with mismatched parameter types.

Common situations: Writing a custom local stub for client-side caching/validation logic but forgetting to add the constructor Dubbo mandates. Copying a stub class from another interface without updating the constructor parameter type. Using an older stub pattern (no-arg init) incompatible with Dubbo's required signature.

Related errors


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