quarkusio/quarkus · error · AmbiguousResolutionException
${beans}
Error message
${beans} What it means
This AmbiguousResolutionException is thrown during type-safe resolution when more than one bean matches an injection point and ArC's built-in disambiguation (priorities, alternatives, etc., via Beans.resolveAmbiguity) cannot select a unique bean. The message is simply the string representation of the ambiguous bean set.
Source
Thrown at independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/BeanResolverImpl.java:69
} else if (beans.size() == 1) {
ret = Set.of(beans.get(0));
} else {
ret = new HashSet<>(beans);
}
return ret;
}
@Override
public BeanInfo resolveAmbiguity(Set<BeanInfo> beans) {
if (beans == null || beans.isEmpty()) {
return null;
}
if (beans.size() > 1) {
BeanInfo selected = Beans.resolveAmbiguity(beans);
if (selected != null) {
return selected;
}
throw new AmbiguousResolutionException(beans.toString());
} else {
return beans.iterator().next();
}
}
@Override
public boolean matches(BeanInfo bean, TypeAndQualifiers typeAndQualifiers) {
return matches(bean, typeAndQualifiers.type, typeAndQualifiers.qualifiers);
}
@Override
public boolean matches(BeanInfo bean, Type requiredType, Set<AnnotationInstance> requiredQualifiers) {
// Bean has all the required qualifiers and a bean type that matches the required type
return matchesType(bean, requiredType) && Beans.hasQualifiers(bean, requiredQualifiers);
}
@Override
public boolean matchesType(BeanInfo bean, Type requiredType) {View on GitHub (pinned to e1c734241f)
Solutions
- Add @Priority (or @Alternative + @Priority) to one of the beans to make it the default winner.
- Narrow the injection point with a distinct @Qualifier.
- Use @Named and inject by name, or @Default/@NonDefault qualifiers to separate the beans.
- Remove or veto one of the duplicate beans (@Vetoed or exclude with profile).
Example fix
// before
@ApplicationScoped class A implements Pay {}
@ApplicationScoped class B implements Pay {}
@Inject Pay pay;
// after
@ApplicationScoped
@Priority(1)
@Alternative
class B implements Pay {}
// or add a qualifier
@Qualifier @interface Fast {} Defensive patterns
Strategy: try-catch
Validate before calling
// Pre-check: count matching beans before injection
Set<Bean<?>> matches = beanManager.getBeans(Pay.class);
if (matches.size() > 1) {
System.err.println("Ambiguous beans for Pay: " + matches);
} Try / catch
try {
Pay pay = CDI.current().select(Pay.class).get();
} catch (AmbiguousResolutionException e) {
// pick explicitly: CDI.current().select(Pay.class, new Fast.Literal()).get()
} Prevention
- Give every injectable interface exactly one default implementation
- Use @Alternative + @Priority to mark optional winners
- Define and use custom qualifiers instead of relying on type alone
When it happens
Trigger: An injection point resolves to two or more beans with identical types and qualifiers, and none is an @Alternative/@Priority winner or @Singleton-defaulted; resolveAmbiguity in BeanResolverImpl is called with beans.size() > 1.
Common situations: Two classes implementing the same interface with the same qualifier; an @Alternative missing @Priority; duplicate producer methods producing the same type; adding a library that registers a conflicting bean.
Related errors
- Unsupported injection point target: <injectionPoint>
- Multiple beans found for localized interface [{e.value}] and
- No template location specified
- Method ${method} of class ${beanClass} is not a producer met
- Injected field cannot be annotated with @Produces: ${field}
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/f56d2999289b6caa.
Report an issue: GitHub.