quarkusio/quarkus · error · AmbiguousResolutionException

More than one active bean found: " + list

Error message

More than one active bean found: " + list

What it means

Thrown by InjectableInstance.getActive() when more than one bean matches the required type and qualifiers and is active. getActive() is a convenience for unambiguous resolution, so CDI's ambiguity rule makes multiple candidates fatal. The exception message lists all conflicting beans.

Source

Thrown at independent-projects/arc/runtime/src/main/java/io/quarkus/arc/InjectableInstance.java:101

    default T orNull() {
        return orElse(null);
    }

    /**
     * Returns exactly one instance of an {@linkplain InjectableBean#checkActive() active} bean that matches
     * the required type and qualifiers. If no active bean matches, or if more than one active bean matches,
     * throws an exception.
     *
     * @return the single instance of an active matching bean
     */
    default T getActive() {
        List<T> list = listActive();
        if (list.size() == 1) {
            return list.get(0);
        } else if (list.isEmpty()) {
            throw new UnsatisfiedResolutionException("No active bean found");
        } else {
            throw new AmbiguousResolutionException("More than one active bean found: " + list);
        }
    }

    /**
     * Returns the list of instances of {@linkplain InjectableBean#checkActive() active} beans that match
     * the required type and qualifiers, sorter in priority order (higher priority goes first).
     *
     * @return the list of instances of matching active beans
     */
    default List<T> listActive() {
        return handlesStream().filter(it -> it.getBean().isActive()).map(InstanceHandle::get).toList();
    }
}

View on GitHub (pinned to e1c734241f)

Solutions

  1. Add a qualifier annotation to distinguish the beans and inject with that qualifier
  2. Use @Alternative + @Priority (or quarkus.arc.select-alternatives) so only one candidate is active for the injection point
  3. Replace getActive() with select(qualifier).get() to narrow the selection programmatically
  4. Remove or exclude the duplicate bean (e.g. via @Exclude or removing the @Produces/@ApplicationScoped)
  5. Inspect the exception message list to identify the conflicting bean classes

Example fix

// before
PaymentService svc = instance.getActive(); // AmbiguousResolutionException
// after
@Priority(1) @Alternative @ApplicationScoped
class MockPaymentService implements PaymentService { }
// or narrow:
PaymentService svc = instance.select(MockPaymentService.Literal.INSTANCE).get();
Defensive patterns

Strategy: validation

Validate before calling

List<PaymentService> all = instance.select(PaymentService.class).handlesStream().map(Instance.Handle::get).toList();
if (all.size() != 1) throw new IllegalStateException("Expected exactly 1 PaymentService bean, found: " + all.size());

Type guard

if (instance.isAmbiguous()) { /* narrow with qualifier or alternative */ }

Try / catch

try { svc = instance.getActive(); } catch (AmbiguousResolutionException e) { log.errorf("Ambiguous beans: %s", e.getMessage()); svc = instance.select(Default.Literal.INSTANCE).get(); }

Prevention

When it happens

Trigger: Calling Instance<Foo>.getActive() (or getHandler().get()) when listActive() returns more than one active bean — i.e. two or more beans of the same type (and qualifiers) exist, e.g. via @Alternative mishandling, duplicate @Priority, or accidentally adding a second bean class.

Common situations: Adding a second implementation of an interface without distinguishing qualifiers; forgetting to enable an @Alternative with @Priority so both implementations match; a library and app both exposing the same bean; tests where a mock bean was registered alongside the real one.

Related errors


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