apache/dubbo · error · IllegalArgumentException
Expect only one but found ${size} matched constructors for t
Error message
Expect only one but found ${size} matched constructors for type: ${type}, matched constructors: ${matchedConstructors} What it means
Thrown by InstantiationStrategy.instantiate when more than one public constructor matches Dubbo's rule (all parameters assignable to ScopeModel subclasses, after removing the default constructor). Dubbo picks a single matched constructor to inject scope models into; multiple candidates are ambiguous, so it refuses to guess and lists them. IllegalArgumentException, surfaced wrapped as ScopeBeanException by callers.
Source
Thrown at dubbo-common/src/main/java/org/apache/dubbo/common/beans/support/InstantiationStrategy.java:77
List<Constructor<?>> matchedConstructors = new ArrayList<>();
Constructor<?>[] declaredConstructors = type.getConstructors();
for (Constructor<?> constructor : declaredConstructors) {
if (isMatched(constructor)) {
matchedConstructors.add(constructor);
}
}
// remove default constructor from matchedConstructors
if (defaultConstructor != null) {
matchedConstructors.remove(defaultConstructor);
}
// match order:
// 1. the only matched constructor with parameters
// 2. default constructor if absent
Constructor<?> targetConstructor;
if (matchedConstructors.size() > 1) {
throw new IllegalArgumentException("Expect only one but found " + matchedConstructors.size()
+ " matched constructors for type: " + type.getName() + ", matched constructors: "
+ matchedConstructors);
} else if (matchedConstructors.size() == 1) {
targetConstructor = matchedConstructors.get(0);
} else if (defaultConstructor != null) {
targetConstructor = defaultConstructor;
} else {
throw new IllegalArgumentException("None matched constructor was found for type: " + type.getName());
}
// create instance with arguments
Class<?>[] parameterTypes = targetConstructor.getParameterTypes();
Object[] args = new Object[parameterTypes.length];
for (int i = 0; i < parameterTypes.length; i++) {
args[i] = getArgumentValueForType(parameterTypes[i]);
}
return (T) targetConstructor.newInstance(args);
}View on GitHub (pinned to 3a3043227f)
Solutions
- Keep exactly one public constructor that takes ScopeModel arguments (consolidate onto ScopeModel or ApplicationModel).
- If two constructors are genuinely needed, make all but one non-public or parameterized by non-ScopeModel types so only one matches isMatched.
- Prefer a single (ScopeModel) constructor and obtain specific models via scopeModelAccessor inside the bean.
- As a fallback, register an explicit Supplier/instance so InstantiationStrategy.instantiate is bypassed.
Example fix
// before
public class MyExt {
public MyExt(ApplicationModel app) { ... }
public MyExt(FrameworkModel fw) { ... } // both match -> ambiguous
}
// after
public class MyExt {
public MyExt(ScopeModel scope) {
this.app = scope.getDefaultAppModel();
}
} Defensive patterns
Strategy: validation
Validate before calling
// Ensure at most one ScopeModel-arg public constructor exists
boolean singleScopeConstructor(Class<?> c) {
int matched = 0;
Constructor<?> def = null;
try { def = c.getConstructor(); } catch (NoSuchMethodException ignored) {}
for (Constructor<?> ctor : c.getConstructors()) {
if (ctor.equals(def)) continue;
boolean ok = true;
for (Class<?> p : ctor.getParameterTypes())
ok &= org.apache.dubbo.rpc.model.ScopeModel.class.isAssignableFrom(p);
if (ok) matched++;
}
return matched <= 1;
} Prevention
- Design extension classes with at most one public ScopeModel-arg constructor.
- If multiple models are needed, accept the base ScopeModel and derive the rest from it.
- If you must keep several constructors, make all but one non-public or non-matching.
- Register an explicit Supplier/instance to bypass reflective constructor matching.
When it happens
Trigger: A class instantiated via InstantiationStrategy (SPI extension or registered bean) that has two or more public constructors whose parameters are all ScopeModel/ApplicationModel/FrameworkModel/ModuleModel types. E.g. constructors (ApplicationModel) and (FrameworkModel) both pass isMatched.
Common situations: Extension classes written with multiple scope-model constructors; refactoring that added a second constructor taking a different ScopeModel subclass; SPI implementation upgraded to support multiple model types simultaneously.
Related errors
- None matched constructor was found for type: ${type}
- create bean instance failed, type=${className}
- unable to determine bean class from factory's superclass or
- No instance of 'FileCacheStoreFactory' for you!
- No instance of 'ConfigurationUtils' for you!
AI-assisted analysis of apache/dubbo@3a3043227f (2026-08-14).
Data as JSON: /api/errors/cec26004731910b1.
Report an issue: GitHub.