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

  1. Keep exactly one JAX-RS parameter annotation per constructor parameter
  2. Move extra parameter values to method-level @PathParam/@QueryParam injection on the resource method instead of the constructor
  3. 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

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


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