quarkusio/quarkus · error · DeploymentException
Cannot have more than one of @PathParam, @QueryParam, @Heade
Error message
Cannot have more than one of @PathParam, @QueryParam, @HeaderParam, @FormParam, @CookieParam, @BeanParam, @Context on
What it means
A single parameter (or field of a bean) may carry at most one request-data annotation among @PathParam, @QueryParam, @HeaderParam, @FormParam, @CookieParam, @BeanParam, @Context (and their @Rest* counterparts). Binding one parameter to two sources is ambiguous, so EndpointIndexer fails deployment via the moreThanOne(...) check.
Source
Thrown at independent-projects/resteasy-reactive/common/processor/src/main/java/org/jboss/resteasy/reactive/common/processor/EndpointIndexer.java:1303
AnnotationInstance cookieParam = anns.get(COOKIE_PARAM);
AnnotationInstance restPathParam = anns.get(REST_PATH_PARAM);
AnnotationInstance restQueryParam = anns.get(REST_QUERY_PARAM);
AnnotationInstance restHeaderParam = anns.get(REST_HEADER_PARAM);
AnnotationInstance restFormParam = anns.get(REST_FORM_PARAM);
AnnotationInstance restMatrixParam = anns.get(REST_MATRIX_PARAM);
AnnotationInstance restCookieParam = anns.get(REST_COOKIE_PARAM);
AnnotationInstance contextParam = anns.get(CONTEXT);
AnnotationInstance defaultValueAnnotation = anns.get(DEFAULT_VALUE);
AnnotationInstance suspendedAnnotation = anns.get(SUSPENDED);
boolean convertible = false;
if (defaultValueAnnotation != null) {
builder.setDefaultValue(defaultValueAnnotation.value().asString());
}
if (handleCustomParameter(anns, builder, paramType, field, methodContext)) {
return builder;
} else if (moreThanOne(pathParam, queryParam, headerParam, formParam, cookieParam, contextParam, beanParam,
restPathParam, restQueryParam, restHeaderParam, restFormParam, restCookieParam)) {
throw new DeploymentException(
"Cannot have more than one of @PathParam, @QueryParam, @HeaderParam, @FormParam, @CookieParam, @BeanParam, @Context on "
+ builder.getErrorLocation());
} else if (pathParam != null) {
builder.setName(pathParam.value().asString());
builder.setType(ParameterType.PATH);
convertible = true;
} else if (restPathParam != null) {
builder.setName(parameterNameOrFail(restPathParam.value(), sourceName, "RestPath", builder.getErrorLocation()));
builder.setType(ParameterType.PATH);
convertible = true;
} else if (queryParam != null) {
builder.setName(queryParam.value().asString());
builder.setType(ParameterType.QUERY);
builder.setSeparator(getSeparator(anns));
convertible = true;
} else if (restQueryParam != null) {
builder.setName(parameterNameOrFail(restQueryParam.value(), sourceName, "RestQuery", builder.getErrorLocation()));
builder.setType(ParameterType.QUERY);View on GitHub (pinned to e1c734241f)
Solutions
- Keep exactly one binding annotation per parameter, matching the intended source (path, query, header, form, cookie, or context)
- If the value must come from multiple sources, declare separate parameters and combine them in the method body
- Check custom handleCustomParameter logic/annotations if the parameter intentionally maps via a framework extension
Example fix
// before
public String get(@QueryParam("q") @HeaderParam("x-q") String value) { ... }
// after
public String get(@QueryParam("q") String query, @HeaderParam("x-q") String header) { ... } Defensive patterns
Strategy: validation
Validate before calling
static final Set<Class<?>> BINDING = Set.of(
PathParam.class, QueryParam.class, HeaderParam.class,
FormParam.class, CookieParam.class, BeanParam.class, Context.class);
static void validateOneBindingPerParam(Method m) {
for (java.lang.reflect.Parameter p : m.getParameters()) {
long n = java.util.Arrays.stream(p.getAnnotations())
.filter(a -> BINDING.contains(a.annotationType())
|| a.annotationType().getName().startsWith("io.quarkus.resteasy.reactive"))
.map(a -> a.annotationType().getSimpleName().replace("Rest", ""))
.distinct().count();
if (n > 1) throw new IllegalStateException("Multiple binding annotations on " + p);
}
} Prevention
- One binding annotation per parameter — never stack @QueryParam with @HeaderParam etc.
- If multiple sources are needed, use separate parameters and combine in code
- Use @BeanParam to aggregate multiple bindings into one object instead of stacking annotations
- Add an annotation-scanning unit test over resource classes in CI
When it happens
Trigger: A resource method parameter is annotated with two or more of the binding annotations, e.g. @QueryParam("q") @HeaderParam("x") String v, or a @RestForm that also has @PathParam; also triggered inside @BeanParam field processing.
Common situations: Copy-paste adding a second annotation to switch binding source without removing the first; accidental multi-annotation after merge conflicts; annotation-adding IDE quick-fixes stacking binding annotations.
Related errors
- @Compressed and @Uncompressed cannot be both declared on res
- Parameter: ${i} of the constructor of class '${resourceDotNa
- @UnwrapException is only supported on classes. Offending tar
- Using @UnwrapException without a value is only supported on
- Unable to load handled exception type ${i.getProvidedType()}
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/4394335dae846234.
Report an issue: GitHub.