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

  1. Add @Priority (or @Alternative + @Priority) to one of the beans to make it the default winner.
  2. Narrow the injection point with a distinct @Qualifier.
  3. Use @Named and inject by name, or @Default/@NonDefault qualifiers to separate the beans.
  4. 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

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


AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05). Data as JSON: /api/errors/f56d2999289b6caa. Report an issue: GitHub.