{"record":{"id":"1d785dc6cd4c6d48","repo":"quarkusio/quarkus","slug":"localized-must-be-declared-on-an-interface-loca","errorCode":null,"errorMessage":"@Localized must be declared on an interface: {localized}","messagePattern":"@Localized must be declared on an interface: (.+?)","errorType":"exception","errorClass":"MessageBundleException","httpStatus":null,"severity":"error","filePath":"extensions/qute/deployment/src/main/java/io/quarkus/qute/deployment/MessageBundleProcessor.java","lineNumber":268,"sourceCode":"                    bundles.add(new MessageBundleBuildItem(name, bundleClass, localeToInterface,\n                            localeToFiles, localeToMergeCandidates, defaultLocale));\n                } else {\n                    throw new MessageBundleException(\"@MessageBundle must be declared on an interface: \" + bundleClass);\n                }\n            }\n        }\n\n        // Detect interfaces annotated with @Localized that don't extend a message bundle interface\n        for (AnnotationInstance localizedAnnotation : index.getAnnotations(Names.LOCALIZED)) {\n            if (localizedAnnotation.target().kind() == Kind.CLASS) {\n                ClassInfo localized = localizedAnnotation.target().asClass();\n                if (Modifier.isInterface(localized.flags())) {\n                    if (!localizedInterfaces.contains(localized.name())) {\n                        throw new MessageBundleException(\n                                \"A localized message bundle interface must extend a message bundle interface: \" + localized);\n                    }\n                } else {\n                    throw new MessageBundleException(\"@Localized must be declared on an interface: \" + localized);\n                }\n            }\n        }\n\n        // Generate implementations\n        // name -> impl class\n        Map<String, ClassDesc> generatedImplementations = generateImplementations(bundles, generatedClasses, generatedResources,\n                generatedServiceProviders, messageTemplateMethods, index);\n\n        // Register synthetic beans\n        for (MessageBundleBuildItem bundle : bundles) {\n            ClassInfo bundleInterface = bundle.getDefaultBundleInterface();\n            beanRegistration.getContext().configure(bundleInterface.name())\n                    .addType(bundle.getDefaultBundleInterface().name())\n                    // The default message bundle - add both @Default and @Localized\n                    .addQualifier(DotNames.DEFAULT).addQualifier().annotation(Names.LOCALIZED)\n                    .addValue(\"value\", getDefaultLocale(bundleInterface.declaredAnnotation(Names.BUNDLE), locales)).done()\n                    .unremovable()","sourceCodeStart":250,"sourceCodeEnd":286,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/extensions/qute/deployment/src/main/java/io/quarkus/qute/deployment/MessageBundleProcessor.java#L250-L286","documentation":"@Localized may only be placed on interfaces; it marks a translated message bundle variant. The build-time processor throws when @Localized targets a class, enum, or record, because localization only makes sense as an interface extending a message bundle interface.","triggerScenarios":"Putting @Localized (with @Locale) on a concrete class or abstract class instead of an interface that extends a @MessageBundle interface.","commonSituations":"Mistakenly annotating the implementation class; IDE quick-fix applying annotations to the wrong type; refactorings that converted an interface to a class while keeping annotations.","solutions":["Move @Localized (and @Locale) onto an interface that extends the message bundle interface.","Remove @Localized from the class; the localized variants are generated for you from bundle interfaces plus .properties files if you prefer file-based translation.","Rebuild after moving the annotation."],"exampleFix":"// before\n@Localized\n@Locale(\"de\")\npublic class AppMessagesDe implements AppMessages {...}\n\n// after\n@Localized\n@Locale(\"de\")\npublic interface AppMessagesDe extends AppMessages {\n    @Override\n    String hello(String name);\n}","handlingStrategy":"validation","validationCode":"Class<?> c = AppMessagesDe.class;\nif (c.getAnnotation(Localized.class) != null && !c.isInterface()) {\n    throw new IllegalStateException(\"@Localized must be declared on an interface: \" + c);\n}","typeGuard":"static boolean isLocalizedInterface(Class<?> c) {\n    return c.isInterface() && c.isAnnotationPresent(Localized.class);\n}","tryCatchPattern":null,"preventionTips":["Only apply @Localized/@Locale to interfaces","Use file-based (.properties) localization when interfaces are impractical","Review annotations after any interface-to-class refactoring"],"tags":["quarkus","qute","message-bundle","localization"],"backgroundTag":"message-bundle-annotation-misuse","analyzedSha":"e1c734241f34c7919086ceb4c9262b4a58f6de44","analyzedAt":"2026-09-05T17:01:29.979Z","contentChangedAt":"2026-09-05T17:01:29.979Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}