quarkusio/quarkus · error · RestClientDefinitionException

Duplicate ${annotationName} annotation for parameter: ${name

Error message

Duplicate ${annotationName} annotation for parameter: ${name} on ${target}

What it means

MicroProfile REST Client parameter annotations like @QueryParam and @HeaderParam (and @PathParam/@CookieParam variants) are collected per method parameter. Each parameter may carry only one instance of a given annotation kind; putAllParamAnnotations uses the annotation's 'name' as a map key and throws RestClientDefinitionException when a duplicate name would overwrite existing data.

Source

Thrown at extensions/resteasy-reactive/rest-client/deployment/src/main/java/io/quarkus/rest/client/reactive/deployment/MicroProfileRestClientEnricher.java:361

        Map<String, ParamData> methodLevelParamsByName = new HashMap<>();
        AnnotationInstance methodLevelParam = method.annotation(clientParamAnnotation);
        if (methodLevelParam != null) {
            methodLevelParamsByName.put(methodLevelParam.value("name").asString(),
                    new ParamData(methodLevelParam, interfaceClass));
        }
        putAllParamAnnotations(methodLevelParamsByName, interfaceClass,
                extractAnnotations(method.annotation(clientParamsAnnotation)), annotationName);

        paramFillersByName.putAll(methodLevelParamsByName);
    }

    private void putAllParamAnnotations(Map<String, ParamData> paramMap, ClassInfo interfaceClass,
            AnnotationInstance[] annotations, String annotationName) {
        for (AnnotationInstance annotation : annotations) {
            String name = annotation.value("name").asString();
            if (paramMap.put(name, new ParamData(annotation, interfaceClass)) != null) {
                throw new RestClientDefinitionException("Duplicate " + annotationName + " annotation for parameter: " + name +
                        " on " + annotation.target());
            }
        }
    }

    private void addParam(MethodInfo declaringMethod, MethodCreator methodCreator,
            ParamData paramData, BuildProducer<GeneratedClassBuildItem> generatedClasses,
            IndexView index, DotName clientParamAnnotation, String annotationName, String paramName,
            Supplier<ResultHandle> existenceChecker,
            BiConsumer<BytecodeCreator, ResultHandle> paramAdder) {

        AnnotationInstance annotation = paramData.annotation;
        ClassInfo declaringClass = paramData.definingClass;

        ResultHandle isParamPresent = existenceChecker.get();
        BytecodeCreator creator = methodCreator.ifTrue(isParamPresent).falseBranch();

        String[] values = annotation.value().asStringArray();

View on GitHub (pinned to e1c734241f)

Solutions

  1. Remove the duplicate annotation for that parameter — one @QueryParam("x") per parameter
  2. If both parent and child interfaces declare it, keep only one declaration or remove the override's duplicate
  3. Audit the interface named in 'on ${target}' for repeated annotation names

Example fix

// before
void get(@QueryParam("q") String q, @QueryParam("q") String q2); // duplicate 'q'
// after
void get(@QueryParam("q") String q, @QueryParam("q2") String q2);
Defensive patterns

Strategy: validation

Validate before calling

Set<String> seen = new HashSet<>();
for (Annotation a : param.getAnnotations()) {
    String name = annotationNameOf(a); // e.g. @QueryParam value/name
    if (!seen.add(a.annotationType().getName() + ":" + name)) {
        throw new IllegalStateException("Duplicate " + a.annotationType() + " for parameter");
    }
}

Try / catch

try {
    enricher.collectClientParamData(...);
} catch (RestClientDefinitionException e) {
    if (e.getMessage().startsWith("Duplicate")) { /* deduplicate annotations */ }
    throw e;
}

Prevention

When it happens

Trigger: Two annotations of the same type (e.g. two @QueryParam) targeting the same parameter name across the client interface hierarchy, or one annotation processed twice for a parameter with identical 'name' values.

Common situations: Copy-paste duplicates in an interface; inheriting annotated methods from a parent interface where a child re-declares the same parameter annotation; IDE auto-completion inserting a second @QueryParam on one parameter.

Related errors


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