quarkusio/quarkus · error · AmbiguousResolutionException

Beans: " + resolvedBeans

Error message

Beans: " + resolvedBeans

What it means

Arc throws AmbiguousResolutionException when bean resolution for a required type/qualifier set matches more than one bean. CDI requires exactly one bean to resolve an injection point; the message lists all resolved beans so you can see the conflict. This enforces the CDI 'unresolvable ambiguous dependency' rule at injection time.

Source

Thrown at independent-projects/arc/runtime/src/main/java/io/quarkus/arc/impl/ArcContainerImpl.java:328

    @Override
    public <X> InstanceHandle<X> instance(Type type, Annotation... qualifiers) {
        return instanceHandle(type, qualifiers);
    }

    @Override
    public <T> Supplier<InstanceHandle<T>> beanInstanceSupplier(Class<T> type, Annotation... qualifiers) {
        if (qualifiers == null || qualifiers.length == 0) {
            qualifiers = new Annotation[] { Default.Literal.INSTANCE };
        }
        Resolvable resolvable = new Resolvable(type, qualifiers);
        Set<InjectableBean<?>> resolvedBeans = resolved.getValue(resolvable);
        if (resolvedBeans.isEmpty()) {
            scanRemovedBeans(resolvable);
        }
        Set<InjectableBean<?>> filteredBean = resolvedBeans;
        if (resolvedBeans.size() > 1) {
            throw new AmbiguousResolutionException("Beans: " + resolvedBeans);

        }
        @SuppressWarnings("unchecked")
        InjectableBean<T> bean = filteredBean.size() != 1 ? null
                : (InjectableBean<T>) filteredBean.iterator().next();
        if (bean == null) {
            return null;
        }
        InjectionPoint injectionPoint = InjectionPointImpl.of(type, qualifiers);
        return new Supplier<InstanceHandle<T>>() {
            @Override
            public InstanceHandle<T> get() {
                return beanInstanceHandle(bean, null, injectionPoint, null);
            }
        };
    }

    @Override

View on GitHub (pinned to e1c734241f)

Solutions

  1. Add a distinguishing qualifier (@Named, custom @Qualifier) to the injection point or to one of the beans
  2. Mark all but one of the conflicting beans @Alternative and enable exactly one in application.properties (quarkus.arc.selected-alternatives)
  3. Use programmatic lookup: inject Instance<MyType> and call .select(qualifier).get()
  4. Use @Priority or @Vetoed / remove the unwanted bean from discovery

Example fix

// before
@Inject
GreetingService service; // two implementations -> ambiguous

// after
@Inject
@English
GreetingService service; // qualifier disambiguates
Defensive patterns

Strategy: validation

Validate before calling

Set<Bean<?>> beans = Arc.container().getBeans(MyType.class);
if (beans.size() > 1) {
    throw new IllegalStateException("Ambiguous beans for MyType: " + beans);
}

Try / catch

try {
    service = instance.select(qualifier).get();
} catch (AmbiguousResolutionException e) {
    LOGGER.errorf("Ambiguous beans: %s", e.getMessage());
    service = instance.select(qualifier, AdditionalQualifiers...).get();
}

Prevention

When it happens

Trigger: Calling Instance.get()/beanInstanceSupplier resolution where two or more beans (e.g. two @Alternative-less implementations, or a producer and a class bean) share the required type and qualifiers. Also occurs at container init for programmatic lookup of a type satisfied by multiple beans.

Common situations: Adding a second implementation of an interface without @Alternative/@Named/@Unique qualifier; a library bean and an application bean both exposing the same API; upgrading a dependency that now registers an extra bean; forgetting to enable only one @Alternative.

Related errors


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