quarkusio/quarkus · error · RestClientDefinitionException
Duplicate ClientHeaderParam annotation for header: ${headerN
Error message
Duplicate ClientHeaderParam annotation for header: ${headerName} on ${target} What it means
Two @ClientHeaderParam annotations for the same header name were found on the client interface (e.g. at both the class and method level, or in repeated containers). Since only one value can be sent per header, the enricher throws during putAllHeaderAnnotations instead of silently choosing one.
Source
Thrown at extensions/resteasy-reactive/rest-client/deployment/src/main/java/io/quarkus/rest/client/reactive/deployment/MicroProfileRestClientEnricher.java:742
* @param javaMethodField method reference in a static class field
* @param methodCreator method for which we put the java.lang.reflect.Method to context (aka this method)
* @param invocationBuilder Invocation.Builder in this method
*/
private void addJavaMethodToContext(FieldDescriptor javaMethodField, MethodCreator methodCreator,
AssignableResultHandle invocationBuilder) {
ResultHandle javaMethod = methodCreator.readStaticField(javaMethodField);
ResultHandle javaMethodAsObject = methodCreator.checkCast(javaMethod, Object.class);
methodCreator.assign(invocationBuilder,
methodCreator.invokeInterfaceMethod(INVOCATION_BUILDER_PROPERTY_METHOD, invocationBuilder,
methodCreator.load(INVOKED_METHOD_PROP), javaMethodAsObject));
}
private void putAllHeaderAnnotations(Map<String, ParamData> headerMap, ClassInfo interfaceClass,
AnnotationInstance[] annotations) {
for (AnnotationInstance annotation : annotations) {
String headerName = annotation.value("name").asString();
if (headerMap.put(headerName, new ParamData(annotation, interfaceClass)) != null) {
throw new RestClientDefinitionException("Duplicate ClientHeaderParam annotation for header: " + headerName +
" on " + annotation.target());
}
}
}
// fillHeaders takes `MultivaluedMap<String, String>` as param and modifies it
private void addHeaderParam(MethodInfo declaringMethod, MethodCreator fillHeadersCreator,
ParamData paramData,
BuildProducer<GeneratedClassBuildItem> generatedClasses,
String fillerClassName,
IndexView index) {
AnnotationInstance annotation = paramData.annotation;
ClassInfo declaringClass = paramData.definingClass;
String headerName = annotation.value("name").asString();
String[] values = annotation.value().asStringArray();View on GitHub (pinned to e1c734241f)
Solutions
- Remove the duplicate @ClientHeaderParam for that header name
- Keep a single definition at the class level if it applies everywhere
- Rename the header if two distinct headers were intended
Example fix
// before
@ClientHeaderParam(name = "Auth", value = "a")
interface Client { @ClientHeaderParam(name = "Auth", value = "b") String get(); }
// after
@ClientHeaderParam(name = "Auth", value = "a")
interface Client { String get(); } Defensive patterns
Strategy: validation
Validate before calling
// Collect header names at startup to detect duplicates
Map<String,Integer> seen = new HashMap<>();
for (ClientHeaderParam a : iface.getAnnotationsByType(ClientHeaderParam.class))
seen.merge(a.name(), 1, Integer::sum);
List<String> dupes = seen.entrySet().stream().filter(e -> e.getValue() > 1).map(Map.Entry::getKey).toList();
if (!dupes.isEmpty()) throw new IllegalStateException("Duplicate headers: " + dupes); Prevention
- Define each header once, at class level when it applies everywhere
- Search the interface (and parents) before adding @ClientHeaderParam
- Avoid copy-pasting method-level annotations that repeat class-level headers
When it happens
Trigger: Applying @ClientHeaderParam(name="Authorization") on both the interface and a method, or repeating the annotation for the same name; the map put returns a previous entry and the build fails.
Common situations: Copy-pasting method-level annotations after a class-level one already defines the header; inheritance from a base interface re-declaring the same header.
Related errors
- Duplicate ${annotationName} annotation for parameter: ${name
- Unable to determine the proper baseUrl/baseUri. Consider reg
- Class ${className} used in ${annotationName} on ${declaringC
- ${annotationName} method ${declaringClass}#${staticMethodNam
- ${annotationName} method ${methodName} not found on ${declar
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/8401c0deccdcbffa.
Report an issue: GitHub.