quarkusio/quarkus · error · java.lang.IllegalStateException

Multiple beans found for localized interface [{e.value}] and

Error message

Multiple beans found for localized interface [{e.value}] and locale [{e.key}]

What it means

When setting up namespace resolvers, MessageBundles expects exactly one CDI bean per localized interface + locale. If container.select(...) finds multiple matching beans (ambiguous resolution), it throws IllegalStateException('Multiple beans found for localized interface ... and locale ...') instead of guessing.

Source

Thrown at extensions/qute/runtime/src/main/java/io/quarkus/qute/i18n/MessageBundles.java:123

        ArcContainer container = Arc.container();
        // For every bundle register a new resolver
        for (Entry<String, Map<String, Class<?>>> entry : context.get().getBundleInterfaces().entrySet()) {
            final String bundleName = entry.getKey();
            final Map<String, Resolver> interfaces = new HashMap<>();
            Resolver resolver = null;
            for (Entry<String, Class<?>> locEntry : entry.getValue().entrySet()) {
                if (locEntry.getKey().equals(DEFAULT_LOCALE)) {
                    resolver = (Resolver) container.select(locEntry.getValue(), Default.Literal.INSTANCE).get();
                    continue;
                }
                Instance<?> found = container.select(locEntry.getValue(), new Localized.Literal(locEntry.getKey()));
                if (found.isUnsatisfied()) {
                    throw new IllegalStateException(
                            Qute.fmt("Bean not found for localized interface [{e.value}] and locale [{e.key}]")
                                    .data("e", locEntry).render());
                }
                if (found.isAmbiguous()) {
                    throw new IllegalStateException(
                            Qute.fmt("Multiple beans found for localized interface [{e.value}] and locale [{e.key}]")
                                    .data("e", locEntry).render());
                }
                interfaces.put(locEntry.getKey(), (Resolver) found.get());
            }
            final Resolver defaultResolver = resolver;

            builder.addNamespaceResolver(new NamespaceResolver() {
                @Override
                public CompletionStage<Object> resolve(EvalContext context) {
                    Object locale = context.getAttribute(ATTRIBUTE_LOCALE);
                    if (locale == null) {
                        Object selectedVariant = context.getAttribute(TemplateInstance.SELECTED_VARIANT);
                        if (selectedVariant != null) {
                            locale = ((Variant) selectedVariant).getLocale();
                        }
                        if (locale == null) {
                            return defaultResolver.resolve(context);

View on GitHub (pinned to e1c734241f)

Solutions

  1. Remove or rename the duplicate localized bundle so only one bean exists per interface+locale
  2. Mark one bean @Alternative/@Priority if intentional overriding is needed
  3. Ensure each @Localized annotation value is unique per bundle interface

Example fix

// before
delete AppMessagesDeCopy.java // duplicate @Localized("de") interface
// after
keep single @Localized("de") AppMessagesDe interface
Defensive patterns

Strategy: validation

Validate before calling

// Detect duplicates before startup: at most one @Localized bean per locale per bundle interface
Map<String,Long> dupes = localizedBeans.stream()
    .collect(Collectors.groupingBy(b -> b.getAnnotation(Localized.class).value(), Collectors.counting()));
dupes.entrySet().stream().filter(e -> e.getValue() > 1).forEach(e -> {
    throw new IllegalStateException("Duplicate @Localized(" + e.getKey() + ") bundle");
});

Try / catch

try {
    startNamespaceResolvers();
} catch (IllegalStateException e) {
    if (e.getMessage().startsWith("Multiple beans found")) {
        throw new IllegalStateException("Remove the duplicate @Localized bundle for this locale", e);
    }
    throw e;
}

Prevention

When it happens

Trigger: Two or more beans implementing the same bundle interface carry qualifiers that resolve to the same @Localized locale lookup — e.g. duplicate @Localized("de") interfaces, or an implementation bean added alongside the generated bundle bean.

Common situations: Authoring the same localized bundle twice under different class names; a manual @Produces/@Alternative bean colliding with the generated one; copying bundle interfaces between packages creating duplicate @Localized values.

Related errors


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