quarkusio/quarkus · error · AmbiguousResolutionException

Beans:

Error message

Beans: 

What it means

When Instance resolution finds more than one bean matching the required type and qualifiers, ArC throws AmbiguousResolutionException('Beans: ' + list). The message enumerates the ambiguous beans so you can see exactly which candidates conflict.

Source

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

                    if (resetCurrentInjectionPoint) {
                        InjectionPointProvider.setCurrent(context, prev);
                    }
                }
            }
        },
                // If @Dependent we need to remove the instance from the CC of this InjectableInstance
                Dependent.class.equals(bean.getScope()) ? this::destroy : null);
    }

    @SuppressWarnings("unchecked")
    private InjectableBean<T> bean() {
        List<InjectableBean<?>> beans = beans();
        if (beans.isEmpty()) {
            ArcContainerImpl.instance().scanRemovedBeans(requiredType, requiredQualifiers.toArray(new Annotation[] {}));
            throw new UnsatisfiedResolutionException(
                    "No bean found for required type [" + requiredType + "] and qualifiers [" + requiredQualifiers + "]");
        } else if (beans.size() > 1) {
            throw new AmbiguousResolutionException("Beans: " + beans.toString());
        }
        return (InjectableBean<T>) beans.iterator().next();
    }

    public boolean hasDependentInstances() {
        return creationalContext.hasDependentInstances();
    }

    @Override
    public void clearCache() {
        if (cachedGetResult.isSet()) {
            creationalContext.release();
            cachedGetResult.clear();
        }
    }

    private T getInternal() {
        return getBeanInstance(bean());

View on GitHub (pinned to e1c734241f)

Solutions

  1. Add a distinguishing qualifier annotation to each implementation and select with it
  2. Mark one implementation @Alternative (and activate it in application.properties) or @Default/@Priority
  3. Narrow the select() call with additional qualifiers so only one bean matches
  4. If one bean should never be used, make it @Vetoed or remove it

Example fix

// before
instance.select(PaymentService.class).get(); // 2 impls -> ambiguous
// after
@Qualifier @Retention(RUNTIME) @interface Stripe {}
instance.select(PaymentService.class, new Stripe.Literal()).get();
Defensive patterns

Strategy: validation

Validate before calling

Instance<PaymentService> candidates = instance.select(PaymentService.class, qualifier);
if (candidates.isAmbiguous()) {
    throw new IllegalStateException("Multiple beans for PaymentService: add a qualifier or @Alternative");
}

Type guard

static <T> T unique(Instance<T> i) {
    if (i.isAmbiguous()) throw new IllegalStateException("Ambiguous: " + i.stream().map(b -> b.getBean().getBeanClass()).toList());
    if (i.isUnsatisfied()) throw new IllegalStateException("Unsatisfied");
    return i.get();
}

Try / catch

try {
    svc = instance.select(PaymentService.class).get();
} catch (AmbiguousResolutionException e) {
    log.errorf("Ambiguous beans: %s — add qualifier/Alternative", e.getMessage());
    throw e;
}

Prevention

When it happens

Trigger: Calling instance.get()/getHandle() after select() where two or more beans match the type and qualifiers — e.g. two implementations of the same interface with the same/default qualifiers.

Common situations: Adding a second implementation of an interface used elsewhere with default qualifiers; a library upgrade introduces a bean that duplicates an app bean; forgotten @Alternative/@Default differentiation.

Related errors


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