quarkusio/quarkus · error · IllegalArgumentException
Parameter: ${i} of the constructor of class '${resourceDotNa
Error message
Parameter: ${i} of the constructor of class '${resourceDotName}' contains multiple JAX-RS annotations, which is not valid What it means
Quarkus RESTEasy Reactive generates CDI producers for resource classes that have non-default constructors, so constructor parameters annotated with JAX-RS parameter annotations (@QueryParam, @PathParam, @MatrixParam, @CookieParam) can be resolved from the request. Each constructor parameter may carry at most ONE such JAX-RS annotation; when the generator finds two or more on the same parameter it aborts deployment with this IllegalArgumentException.
Source
Thrown at extensions/resteasy-reactive/rest/deployment/src/main/java/io/quarkus/resteasy/reactive/server/deployment/CustomResourceProducersGenerator.java:245
List<CtorParamData> ctorParamData = new ArrayList<>(ctor.parametersCount());
for (short i = 0; i < ctor.parametersCount(); i++) {
Type parameterType = ctor.parameterType(i);
if (!paramIndexToAnnotations.containsKey(i)) {
ctorParamData.add(new CtorParamData(CtorParamData.CustomProducerParameterType.OTHER, parameterType));
} else {
List<AnnotationInstance> paramAnnotations = paramIndexToAnnotations.get(i);
List<AnnotationInstance> jaxRSAnnotationsOfParam = new ArrayList<>(paramAnnotations.size());
for (AnnotationInstance paramAnnotation : paramAnnotations) {
if (ResteasyReactiveDotNames.RESOURCE_CTOR_PARAMS_THAT_NEED_HANDLING
.contains(paramAnnotation.name())) {
jaxRSAnnotationsOfParam.add(paramAnnotation);
}
}
if (jaxRSAnnotationsOfParam.isEmpty()) {
ctorParamData
.add(new CtorParamData(CtorParamData.CustomProducerParameterType.OTHER, parameterType));
} else if (jaxRSAnnotationsOfParam.size() > 1) {
throw new IllegalArgumentException("Parameter: " + i + " of the constructor of class '"
+ resourceDotName + "' contains multiple JAX-RS annotations, which is not valid");
} else {
AnnotationInstance jaxRSAnnotationOfParam = jaxRSAnnotationsOfParam.iterator().next();
if (!parameterType.name().equals(ResteasyReactiveDotNames.STRING)) {
// TODO: do we need to support converters here?
throw new IllegalArgumentException("Parameter: " + i + " of the constructor of class '"
+ resourceDotName + "' which is annotated with '" + jaxRSAnnotationOfParam.name()
+ "' can only be of type String");
}
CtorParamData.CustomProducerParameterType customProducerParameterType;
if (jaxRSAnnotationOfParam.name().equals(ResteasyReactiveDotNames.QUERY_PARAM)) {
customProducerParameterType = CtorParamData.CustomProducerParameterType.QUERY;
} else if (jaxRSAnnotationOfParam.name().equals(ResteasyReactiveDotNames.HEADER_PARAM)) {
customProducerParameterType = CtorParamData.CustomProducerParameterType.HEADER;
} else if (jaxRSAnnotationOfParam.name().equals(ResteasyReactiveDotNames.PATH_PARAM)) {
customProducerParameterType = CtorParamData.CustomProducerParameterType.PATH;
} else if (jaxRSAnnotationOfParam.name().equals(ResteasyReactiveDotNames.MATRIX_PARAM)) {
customProducerParameterType = CtorParamData.CustomProducerParameterType.MATRIX;View on GitHub (pinned to e1c734241f)
Solutions
- Keep exactly one JAX-RS parameter annotation per constructor parameter
- Move extra parameter values to method-level @PathParam/@QueryParam injection on the resource method instead of the constructor
- If a value is needed in two forms, inject it once in the constructor and derive the other in the class body
Example fix
// before
public MyResource(@QueryParam("q") @PathParam("id") String value) { ... }
// after
public MyResource(@QueryParam("q") String value) { ... } Defensive patterns
Strategy: validation
Validate before calling
// before build, per resource constructor parameter
long jaxrsParamCount = Stream.of(param.getAnnotations())
.map(Annotation::annotationType)
.map(Class::getName)
.filter(n -> n.equals("jakarta.ws.rs.QueryParam") || n.equals("jakarta.ws.rs.PathParam")
|| n.equals("jakarta.ws.rs.MatrixParam") || n.equals("jakarta.ws.rs.CookieParam"))
.count();
if (jaxrsParamCount > 1) throw new IllegalStateException("At most one JAX-RS param annotation allowed per constructor parameter"); Prevention
- Give each constructor parameter exactly one JAX-RS parameter annotation
- Review constructor signatures of resources with non-default constructors after refactoring
- Prefer method-parameter injection for REST parameters
- Keep a checkstyle/architectural rule forbidding stacked param annotations
When it happens
Trigger: A @Path resource class has a non-default constructor and one constructor parameter is annotated with two or more JAX-RS parameter annotations simultaneously (e.g. both @QueryParam and @PathParam on the same parameter). Detected during the Quarkus build when CustomResourceProducersGenerator.generate() processes the constructor.
Common situations: Copy-pasting annotations between parameters, refactoring a method signature into a constructor and accidentally stacking annotations, or mixing @PathParam with @QueryParam when a resource is served from multiple sub-locations.
Related errors
- Parameter: ${i} of the constructor of class '${resourceDotNa
- Unsupported type '${jaxRSAnnotationOfParam.name()}' used as
- Unable to load handled exception type ${i.getProvidedType()}
- '@FormParam' and '@RestForm' cannot be used in a resource me
- '@FormParam' and '@RestForm' can only be used on methods ann
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/f7924012489d53ae.
Report an issue: GitHub.