quarkusio/quarkus · error · MessageBundleException

Duplicate key [ ] found on

Error message

Duplicate key [%s] found on %s

What it means

Within one message bundle interface, each resolved message key must be unique. getKey() derives the key from the method name or @Message#key; if two methods resolve to the same key, template lookup would be ambiguous, so the build fails with the duplicate key and the bundle interface.

Solutions

  1. Rename one of the methods or set a distinct @Message(key = "...") so each key is unique.
  2. Remove the redundant duplicate method if it serves the same message.
  3. Search the bundle interface for repeated method names and @Message key values before rebuilding.

Example fix

// before
String hello();
@Message(key = "hello")
String hi();

// after
String hello();
@Message(key = "hi")
String hi();
Defensive patterns

Strategy: validation

Validate before calling

// Detect duplicate keys in a bundle interface
java.util.Map<String,Integer> seen = new java.util.HashMap<>();
for (java.lang.reflect.Method m : AppMessages.class.getDeclaredMethods()) {
    Message msg = m.getAnnotation(Message.class);
    String key = (msg != null && !Message.DEFAULT_NAME.equals(msg.key())) ? msg.key() : m.getName();
    if (seen.put(key, 1) != null) throw new IllegalStateException("Duplicate key: " + key);
}

Prevention

When it happens

Trigger: Two methods mapping to the same key, e.g. `String hello();` and `@Message(key="hello") String hi();`, or overloads whose keys collapse (same name, same key derivation).

Common situations: Copy-pasting a method and forgetting to rename it or its @Message key; adding an overload of an existing bundle method (keys don't consider parameters); merging branches that both added a method with the same key.

Related errors


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

Appendix: source

Thrown at extensions/qute/deployment/src/main/java/io/quarkus/qute/deployment/MessageBundleProcessor.java:1070

                        messageAnnotation = defaultBundleMethod.annotation(Names.MESSAGE);
                    } else {
                        messageAnnotation = method.annotation(Names.MESSAGE);
                    }

                    if (messageAnnotation == null) {
                        LOG.debugf("@Message not declared on %s#%s - using the default key/value", bundleInterface, method);
                        messageAnnotation = AnnotationInstance.builder(Names.MESSAGE).value(Message.DEFAULT_VALUE)
                                .add("name", Message.DEFAULT_NAME).build();
                    }

                    String key = getKey(method, messageAnnotation, defaultKeyValue);
                    if (key.equals(MESSAGE)) {
                        throw new MessageBundleException(String.format(
                                "A message bundle interface method must not use the key 'message' which is reserved for dynamic lookup; defined for %s#%s()",
                                bundleInterface, method.name()));
                    }
                    if (keyMap.containsKey(key)) {
                        throw new MessageBundleException(String.format("Duplicate key [%s] found on %s", key, bundleInterface));
                    }
                    keyMap.put(key, new SimpleMessageMethod(method));

                    boolean generatedTemplate = false;
                    String messageTemplate = messageTemplates.get(method.name());
                    if (messageTemplate == null) {
                        messageTemplate = getMessageAnnotationValue(messageAnnotation, true);
                    }

                    if (messageTemplate == null && defaultBundleInterface != null) {
                        // method is annotated with @Message without value() -> fallback to default locale
                        messageTemplate = getMessageAnnotationValue((defaultBundleInterface.method(method.name(),
                                method.parameterTypes().toArray(new Type[] {}))).annotation(Names.MESSAGE), true);
                    }

                    // We need some special handling for enum message bundle methods
                    // A message bundle method that accepts an enum and has no message template receives a generated template:
                    // {#when enumParamName}

View on GitHub (pinned to e1c734241f)