gradle/gradle · error · IllegalArgumentException
%s is a non-static inner class.
Error message
%s is a non-static inner class.
What it means
ParamsMatchingConstructorSelector.forParams can handle inner classes, but only when the enclosing instance is supplied: if the generated class has an outer type and either zero params were given or params[0] is not an instance of the enclosing class, it throws '%s is a non-static inner class.' before matching constructors.
Source
Thrown at platforms/core-configuration/model-core/src/main/java/org/gradle/internal/instantiation/generator/ParamsMatchingConstructorSelector.java:50
@Override
public void vetoParameters(ClassGenerator.GeneratedConstructor<?> constructor, Object[] parameters) {
// Don't care
}
@Override
public <T> ClassGenerator.GeneratedConstructor<? extends T> forType(Class<T> type) throws UnsupportedOperationException {
throw new UnsupportedOperationException("This constructor selector requires the construction parameters");
}
@Override
public <T> ClassGenerator.GeneratedConstructor<? extends T> forParams(final Class<T> type, Object[] params) {
ClassGenerator.GeneratedClass<?> generatedClass = classGenerator.generate(type);
if (generatedClass.getOuterType() != null && (params.length == 0 || !generatedClass.getOuterType().isInstance(params[0]))) {
TreeFormatter formatter = new TreeFormatter();
formatter.node(type);
formatter.append(" is a non-static inner class.");
throw new IllegalArgumentException(formatter.toString());
}
List<? extends ClassGenerator.GeneratedConstructor<?>> constructors = generatedClass.getConstructors();
if (constructors.size() == 1) {
return Cast.uncheckedCast(constructors.get(0));
}
ClassGenerator.GeneratedConstructor<?> match = null;
// NOTE: this relies on the constructors being in a predictable order
// sorted by the number of parameters the constructor requires
for (ClassGenerator.GeneratedConstructor<?> constructor : constructors) {
Class<?>[] parameterTypes = constructor.getParameterTypes();
// The candidate constructor has fewer parameters than the number of
// parameters we were given. This can't be the constructor
if (parameterTypes.length < params.length) {
continue;
}
View on GitHub (pinned to 534f27719b)
Solutions
- Pass the enclosing instance first: newInstance(Inner.class, outerRef, otherArgs...).
- Or make the nested class static / move it to top level so no outer instance is needed.
Example fix
// before instantiator.newInstance(Inner.class, config); // after instantiator.newInstance(Inner.class, outer, config);
Defensive patterns
Strategy: validation
Validate before calling
Class<?> outer = type.getEnclosingClass();
if (outer != null && !Modifier.isStatic(type.getModifiers())
&& (params.length == 0 || !outer.isInstance(params[0]))) {
throw new IllegalArgumentException("pass the outer instance as the first parameter for " + type.getName());
} Prevention
- For inner classes under params matching, always pass the enclosing instance as argument zero.
- Prefer static nested or top-level classes for types created by reflection-based instantiators.
When it happens
Trigger: forParams(Inner.class, ...) with an empty params array, or with the outer instance passed in the wrong position so params[0] is not an instance of the enclosing class.
Common situations: Switching a type to a nested class without updating instantiation call sites; forgetting that under this selector an inner-class construction requires the outer instance as the very first argument.
Related errors
- %s has no constructor that is annotated with @Inject (javax.
- %s is a non-static inner class.
- Multiple constructors for parameters %s candidate: %s best m
- No constructors of type %s match parameters: %s
- Unable to select constructor for non-static inner class %s.
AI-assisted analysis of gradle/gradle@534f27719b (2026-08-22).
Data as JSON: /api/errors/6b25718c5203998c.
Report an issue: GitHub.