apache/dubbo · error · RuntimeException
Illegal constructor: ${cls.getName()}
Error message
Illegal constructor: ${cls.getName()} What it means
When PojoUtils needs to instantiate a class during realization, it first tries the no-arg constructor. If that fails, it checks getDeclaredConstructors(). Per the Java spec, that method returns an empty array for interfaces, primitive types, array classes, and void. An empty array means there is no way to instantiate, so a RuntimeException is thrown naming the class.
Source
Thrown at dubbo-common/src/main/java/org/apache/dubbo/common/utils/PojoUtils.java:694
} catch (Exception t) {
return newInstance(cls);
}
}
private static Object newInstance(Class<?> cls) {
try {
return cls.getDeclaredConstructor().newInstance();
} catch (Exception t) {
Constructor<?>[] constructors = cls.getDeclaredConstructors();
/*
From Javadoc java.lang.Class#getDeclaredConstructors
This method returns an array of Constructor objects reflecting all the constructors
declared by the class represented by this Class object.
This method returns an array of length 0,
if this Class object represents an interface, a primitive type, an array class, or void.
*/
if (constructors.length == 0) {
throw new RuntimeException("Illegal constructor: " + cls.getName());
}
Throwable lastError = null;
Arrays.sort(constructors, Comparator.comparingInt(a -> a.getParameterTypes().length));
for (Constructor<?> constructor : constructors) {
try {
constructor.setAccessible(true);
Object[] parameters = Arrays.stream(constructor.getParameterTypes())
.map(PojoUtils::getDefaultValue)
.toArray();
return constructor.newInstance(parameters);
} catch (Exception e) {
lastError = e;
}
}
throw new RuntimeException(lastError.getMessage(), lastError);
}
}
View on GitHub (pinned to 3a3043227f)
Solutions
- Ensure the target type for realization is a concrete instantiable class with at least one constructor, not an interface or primitive.
- If the type is an interface, provide the concrete implementation class name in the generic map ('class' key) or configure the provider to return a concrete type.
- Check that the method return type or parameter type metadata on the provider side points to a concrete class.
- Verify the GENERIC_WITH_CLZ setting and that the serialized form includes the concrete class name.
Example fix
// before — interface as target type
PojoUtils.realize(map, MyInterface.class);
// after — concrete class
PojoUtils.realize(map, MyInterfaceImpl.class);
// or include class name in the map
map.put("class", "com.example.MyInterfaceImpl");
PojoUtils.realize(map, MyInterface.class); Defensive patterns
Strategy: validation
Validate before calling
// Validate the class is instantiable before passing to realize
if (type.isInterface() || type.isPrimitive() || type.isArray() || type == Void.class) {
throw new IllegalArgumentException(
"Cannot realize into non-instantiable type: " + type.getName()
+ ". Provide a concrete class.");
}
PojoUtils.realize(map, type); Type guard
// Type guard for instantiable types
static boolean isInstantiable(Class<?> cls) {
return !cls.isInterface() && !cls.isPrimitive()
&& !cls.isArray() && cls != Void.class;
} Prevention
- Always target realization at concrete classes, not interfaces or primitives.
- Include the concrete class name in the generic Map ('class' key) so PojoUtils can resolve the implementation.
- Configure provider return/parameter types as concrete classes in the service interface.
When it happens
Trigger: Calling PojoUtils.newInstance(cls) (indirectly via realize) where cls is an interface, a primitive type (int.class), an array class, or void.class. These types have no constructors and cannot be instantiated via reflection.
Common situations: A generic RPC where the target type metadata resolves to an interface instead of a concrete class, or a deserialization target is incorrectly specified as a primitive or array type. The realize0 logic should normally handle interfaces by finding an implementation, but if the code path reaches newInstance with an interface, it fails here.
Related errors
- Failed to set pojo ${dest.getClass().getSimpleName()} proper
- Failed to set field ${name} of pojo ${dest.getClass().getNam
- create bean instance failed, type=${className}
- Expect only one but found ${size} matched constructors for t
- None matched constructor was found for type: ${type}
AI-assisted analysis of apache/dubbo@3a3043227f (2026-08-14).
Data as JSON: /api/errors/9c707732c7929a3f.
Report an issue: GitHub.