quarkusio/quarkus · error · MessageBundleException
@MessageBundle must be declared on an interface: {bundleClas
Error message
@MessageBundle must be declared on an interface: {bundleClass} What it means
Quarkus Qute message bundles are defined as Java interfaces annotated with @MessageBundle. During application build, MessageBundleProcessor.processBundles validates that every class carrying @MessageBundle is actually an interface; if it is a class, enum, or record, the build fails with this MessageBundleException. This is a compile/deploy-time contract check so template resolution can generate a implementing class.
Source
Thrown at extensions/qute/deployment/src/main/java/io/quarkus/qute/deployment/MessageBundleProcessor.java:253
} else {
files = localeToFiles.get(locale);
if (files == null) {
files = new ArrayList<>();
localeToFiles.put(locale, files);
}
}
files.add(messageFile);
}
}
// Check for duplicates again
checkForDuplicates(localeToMergeCandidates);
checkForDuplicates(localeToFiles);
bundles.add(new MessageBundleBuildItem(name, bundleClass, localeToInterface,
localeToFiles, localeToMergeCandidates, defaultLocale));
} else {
throw new MessageBundleException("@MessageBundle must be declared on an interface: " + bundleClass);
}
}
}
// Detect interfaces annotated with @Localized that don't extend a message bundle interface
for (AnnotationInstance localizedAnnotation : index.getAnnotations(Names.LOCALIZED)) {
if (localizedAnnotation.target().kind() == Kind.CLASS) {
ClassInfo localized = localizedAnnotation.target().asClass();
if (Modifier.isInterface(localized.flags())) {
if (!localizedInterfaces.contains(localized.name())) {
throw new MessageBundleException(
"A localized message bundle interface must extend a message bundle interface: " + localized);
}
} else {
throw new MessageBundleException("@Localized must be declared on an interface: " + localized);
}
}
}View on GitHub (pinned to e1c734241f)
Solutions
- Change the annotated type to a Java interface: `@MessageBundle(locale = "en") public interface AppMessages { ... }`
- If a class is required, move the bundle methods into a new interface and have the class consume the generated bundle bean instead.
- Rebuild and confirm the annotation target is reported as an interface in the error location.
Example fix
// before
@MessageBundle(locale = "en")
public class AppMessages {
String hello(String name);
}
// after
@MessageBundle(locale = "en")
public interface AppMessages {
String hello(String name);
} Defensive patterns
Strategy: validation
Validate before calling
// Verify every @MessageBundle target is an interface before building
Class<?> c = AppMessages.class;
if (!c.isInterface() || c.getAnnotation(MessageBundle.class) == null) {
throw new IllegalStateException("@MessageBundle must be on an interface: " + c);
} Type guard
static boolean isValidMessageBundle(Class<?> c) {
return c.isInterface() && c.isAnnotationPresent(MessageBundle.class);
} Prevention
- Always define bundles as interfaces, never classes
- Let annotation-processor errors surface early in dev mode instead of ignoring build output
- Keep bundle interfaces in a dedicated i18n package to avoid accidental class conversion
When it happens
Trigger: Annotating a concrete class, abstract class, enum, or record with @MessageBundle instead of an interface, e.g. `@MessageBundle(locale="en") public class AppMessages {...}`.
Common situations: Copy-pasting the annotation from an interface onto a class; migrating a messages class from another i18n framework (e.g. ResourceBundle-based) without converting it to an interface; auto-generated code that emits classes.
Related errors
- Message bundle name [%s] declared on %s must be a valid name
- Message bundle interface name conflict - [%s] is used for bo
- Locale of [%s] conflicts with the locale [%s] of the default
- Cannot register [%s] - a localized message bundle interface
- A localized message bundle interface must extend a message b
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/be9d830478b6d441.
Report an issue: GitHub.