gradle/gradle · error · IllegalArgumentException
%s has no constructor that is annotated with @Inject (javax.
Error message
%s has no constructor that is annotated with @Inject (javax.inject.Inject) for dependency injection.
What it means
When a type declares multiple constructors, InjectUtil requires exactly one to be annotated with @Inject. If none carries the annotation, constructor selection is impossible and Gradle throws IllegalArgumentException naming the type before instantiation proceeds.
Source
Thrown at platforms/core-configuration/model-core/src/main/java/org/gradle/internal/instantiation/generator/InjectUtil.java:76
formatter.append(" should be ");
appendAnnotatedWithInject(formatter);
throw new IllegalArgumentException(formatter.toString());
}
}
List<ClassGenerator.GeneratedConstructor<T>> injectConstructors = new ArrayList<ClassGenerator.GeneratedConstructor<T>>();
for (ClassGenerator.GeneratedConstructor<T> constructor : constructors) {
if (constructor.getAnnotation(Inject.class) != null) {
injectConstructors.add(constructor);
}
}
if (injectConstructors.isEmpty()) {
TreeFormatter formatter = new TreeFormatter();
formatter.node(reportAs);
formatter.append(" has no constructor that is ");
appendAnnotatedWithInject(formatter);
throw new IllegalArgumentException(formatter.toString());
}
if (injectConstructors.size() > 1) {
TreeFormatter formatter = new TreeFormatter();
formatter.node(reportAs);
formatter.append(" has multiple constructors that are ");
appendAnnotatedWithInject(formatter);
throw new IllegalArgumentException(formatter.toString());
}
return injectConstructors.get(0);
}
private static void appendAnnotatedWithInject(TreeFormatter formatter) {
formatter.append("annotated with @Inject (");
formatter.append(Inject.class.getName());
formatter.append(") for dependency injection.");
}
View on GitHub (pinned to 534f27719b)
Solutions
- Designate one canonical constructor and annotate it with @Inject.
- Delete redundant constructors if they all populate the same fields.
- In Groovy, target the constructor explicitly: @Inject MyType(String name) { }.
Example fix
// before
MyType() {}
MyType(String name) { this.name = name; }
// after
MyType() {}
@Inject
MyType(String name) { this.name = name; } Defensive patterns
Strategy: validation
Validate before calling
long injectCount = Arrays.stream(type.getDeclaredConstructors())
.filter(c -> c.isAnnotationPresent(javax.inject.Inject.class)).count();
if (type.getDeclaredConstructors().length > 1 && injectCount != 1) {
throw new IllegalStateException("type needs exactly one @Inject constructor: " + type.getName());
} Prevention
- Keep exactly one designated injection constructor per type.
- In Groovy, place @Inject directly before the constructor declaration, not on the class.
When it happens
Trigger: A type with overloaded constructors, for example MyType(), MyType(String), MyType(String, int), with no @Inject on any of them, instantiated through the JSR-330 selector.
Common situations: Backwards-compatible constructors accumulated across releases; Lombok-generated constructors plus a hand-written one; Groovy classes where @Inject was placed on the class instead of a constructor.
Related errors
- The constructor for type %s should be public or package prot
- The constructor for type %s should be annotated with @Inject
- %s has multiple constructors that are annotated with @Inject
- %s is a non-static inner class.
- Multiple constructors for parameters %s candidate: %s best m
AI-assisted analysis of gradle/gradle@534f27719b (2026-08-22).
Data as JSON: /api/errors/1297677af53d687a.
Report an issue: GitHub.