quarkusio/quarkus · error · java.lang.IllegalStateException

Unable to obtain a message bundle for interface [{ifacename}

Error message

Unable to obtain a message bundle for interface [{ifacename}]{#if loc} and locale [{loc.value}]{/if}

What it means

MessageBundles.get() obtains the bundle implementation from the CDI container (optionally qualified with @Localized). If no bean is available for the interface (and locale, when a @Localized qualifier is given), it throws IllegalStateException with a Qute-rendered message naming the interface and locale.

Source

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

    }

    public static <T> T get(Class<T> bundleInterface, Localized localized) {
        if (!bundleInterface.isInterface()) {
            throw new IllegalArgumentException("Not a message bundle interface: " + bundleInterface.getName());
        }
        if (!bundleInterface.isAnnotationPresent(MessageBundle.class)
                && !bundleInterface.isAnnotationPresent(Localized.class)) {
            throw new IllegalArgumentException(
                    "Message bundle interface must be annotated either with @MessageBundle or with @Localized: "
                            + bundleInterface.getName());
        }
        ArcContainer container = Arc.requireContainer();
        InstanceHandle<T> handle = localized != null ? container.instance(bundleInterface, localized)
                : container.instance(bundleInterface);
        if (handle.isAvailable()) {
            return handle.get();
        }
        throw new IllegalStateException(Qute.fmt(
                "Unable to obtain a message bundle for interface [{ifacename}]{#if loc} and locale [{loc.value}]{/if}")
                .data("ifacename", bundleInterface.getName())
                .data("loc", localized)
                .render());
    }

    /**
     * Obtains a message bundle for the specified interface and the current locale.
     * <p>
     * The current locale is obtained from a {@link CurrentLocaleProvider} bean. The appropriate localized variant is
     * selected by an exact language tag match first, then by a language-only match. If no provider is available, or the
     * current locale cannot be determined, or no matching localized variant exists, then the bundle for the default
     * locale is returned.
     * <p>
     * This method backs the beans injected with the {@link LocaleAware} qualifier.
     *
     * @param <T>
     * @param bundleInterface

View on GitHub (pinned to e1c734241f)

Solutions

  1. Define a @Localized bean for the requested locale, or request the default bundle without the localized qualifier
  2. Ensure the interface is annotated with @MessageBundle and part of the Quarkus application build
  3. Run inside the Quarkus runtime (ArC container started), not a plain JUnit test without @QuarkusTest
  4. Check quarkus.default-locale / quarkus.locales config to confirm the locale is supported

Example fix

// before
AppMessages m = MessageBundles.get(AppMessages, new Localized.Literal(Locale.FRENCH)); // no fr bundle
// after
@Localized("fr") AppMessagesFr fr; // define/add the fr variant, or use the default bundle
AppMessages m = MessageBundles.get(AppMessages);
Defensive patterns

Strategy: try-catch

Validate before calling

// Before calling get(), ensure the app is running under Quarkus and the locale variant exists
boolean defaultOnly = MessageBundles.getHandle == null; // or check Arc.container() != null
Set<String> availableLocales = Set.of("en", "de"); // mirror your @Localized values
if (!availableLocales.contains(requestedLocale)) { /* fall back to default bundle */ }

Try / catch

try {
    return MessageBundles.get(AppMessages.class, new Localized.Literal(locale));
} catch (IllegalStateException e) {
    if (e.getMessage().startsWith("Unable to obtain a message bundle")) {
        return MessageBundles.get(AppMessages.class); // fall back to default
    }
    throw e;
}

Prevention

When it happens

Trigger: Calling MessageBundles.get(AppMessages.class) (or with a Localized instance) at runtime when the message bundle bean was never registered — e.g. the interface isn't a bean (no @MessageBundle in an unprocessed module), the localized variant for that locale was never defined, or ArC container isn't started.

Common situations: Requesting a locale variant (@Localized('de')) that was never authored; using MessageBundles.get in a non-CDI context/unit test without the Quarkus container; bundle interface living in a library not processed by the Qute extension.

Related errors


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