quarkusio/quarkus · error · DefinitionException
Multiple @Inject constructors found on
Error message
Multiple @Inject constructors found on
What it means
A CDI bean class may declare at most one constructor annotated @Inject (the bean constructor). ArC counts @Inject-annotated constructors during bean processing and throws this DefinitionException (listing all of them) when a bean class has more than one.
Source
Thrown at independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/Injection.java:221
private static void validateInjections(List<Injection> injections, BeanType beanType) {
for (Injection injection : injections) {
for (InjectionPointInfo ipi : injection.injectionPoints) {
validateInjections(ipi, beanType);
}
}
}
static List<Injection> forBean(AnnotationTarget beanTarget, BeanInfo declaringBean, BeanDeployment beanDeployment,
InjectionPointModifier transformer, BeanType beanType) {
if (Kind.CLASS.equals(beanTarget.kind())) {
List<Injection> injections = forClassBean(beanTarget.asClass(), beanTarget.asClass(), beanDeployment,
transformer, false, new HashSet<>());
Set<AnnotationTarget> injectConstructors = injections.stream().filter(Injection::isConstructor)
.map(Injection::getTarget).collect(Collectors.toSet());
if (injectConstructors.size() > 1) {
throw new DefinitionException(
"Multiple @Inject constructors found on " + beanTarget.asClass().name() + ":\n"
+ injectConstructors.stream().map(Object::toString).collect(Collectors.joining("\n")));
}
for (AnnotationTarget injectConstructor : injectConstructors) {
Set<AnnotationInstance> parameterAnnotations = Annotations.getParameterAnnotations(beanDeployment,
injectConstructor.asMethod());
for (AnnotationInstance annotation : parameterAnnotations) {
if (DotNames.DISPOSES.equals(annotation.name())) {
throw new DefinitionException(
"Bean constructor must not have a @Disposes parameter: " + injectConstructor);
}
if (DotNames.OBSERVES.equals(annotation.name())) {
throw new DefinitionException(
"Bean constructor must not have an @Observes parameter: " + injectConstructor);
}
if (DotNames.OBSERVES_ASYNC.equals(annotation.name())) {
throw new DefinitionException(
"Bean constructor must not have an @ObservesAsync parameter: " + injectConstructor);View on GitHub (pinned to e1c734241f)
Solutions
- Remove @Inject from all but one constructor; ArC will pick the single annotated one
- If the class has exactly one constructor, remove @Inject entirely — it is used automatically
- Make the no-arg constructor package-private or remove it if it was only there for frameworks
Example fix
// before
class MyBean { @Inject MyBean() {} @Inject MyBean(Other o) {} }
// after
class MyBean { @Inject MyBean(Other o) {} } Defensive patterns
Strategy: validation
Validate before calling
long n = java.util.Arrays.stream(MyBean.class.getDeclaredConstructors())
.filter(c -> c.isAnnotationPresent(jakarta.inject.Inject.class)).count();
if (n > 1) throw new IllegalStateException("At most one @Inject constructor allowed on MyBean"); Prevention
- At most one @Inject constructor per bean class
- Single-constructor classes need no @Inject at all
- Remove legacy constructors or their @Inject annotations when adding new ones
When it happens
Trigger: Annotating two or more constructors of a bean class with @Inject, e.g. after adding a new constructor with dependencies while leaving @Inject on the old no-arg constructor.
Common situations: Refactoring that adds a constructor for testing while keeping the old @Inject constructor; merge conflicts keeping duplicate constructors; not realizing only one constructor may carry @Inject.
Related errors
- No TCCL available
- Unsupported value:
- Unable to construct type for ${btRemovedBean}: ${e.getMessag
- Multiple disposed parameters found for ${disposerMethod}
- Invalid injection of Interceptor<T> bean, can only be used i
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/f8a7042ff487dea3.
Report an issue: GitHub.