quarkusio/quarkus · error · IllegalArgumentException

Parameter: ${i} of the constructor of class '${resourceDotNa

Error message

Parameter: ${i} of the constructor of class '${resourceDotName}' which is annotated with '${jaxRSAnnotationOfParam.name()}' can only be of type String

What it means

When Quarkus generates custom producers for resource classes with non-default constructors, constructor parameters carrying a JAX-RS parameter annotation must be of type java.lang.String; the generated bytecode injects the raw request value as a String with no converter support. A non-String annotated parameter aborts the build with this IllegalArgumentException.

Source

Thrown at extensions/resteasy-reactive/rest/deployment/src/main/java/io/quarkus/resteasy/reactive/server/deployment/CustomResourceProducersGenerator.java:251

                        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;
                            } else if (jaxRSAnnotationOfParam.name().equals(ResteasyReactiveDotNames.COOKIE_PARAM)) {
                                customProducerParameterType = CtorParamData.CustomProducerParameterType.COOKIE;
                            } else {
                                throw new IllegalStateException("Unsupported type '" + jaxRSAnnotationOfParam.name()
                                        + "' used as an annotation in constructor of class '" + resourceDotName + "'");
                            }

View on GitHub (pinned to e1c734241f)

Solutions

  1. Change the constructor parameter type to String and convert it manually inside the constructor
  2. Move the parameter to the resource method signature where automatic type conversion is supported
  3. Use field injection on a @RequestScoped resource instead of constructor injection

Example fix

// before
public MyResource(@PathParam("id") Long id) { ... }
// after
public MyResource(@PathParam("id") String id) { this.id = Long.valueOf(id); }
Defensive patterns

Strategy: validation

Validate before calling

// ensure annotated constructor params are String
for (Parameter p : ctor.getParameters()) {
    boolean hasJaxrs = Arrays.stream(p.getAnnotations()).anyMatch(a ->
            a.annotationType().getName().startsWith("jakarta.ws.rs."));
    if (hasJaxrs && p.getType() != String.class)
        throw new IllegalStateException("Constructor param " + p.getName() + " must be String");
}

Prevention

When it happens

Trigger: A resource class constructor parameter is annotated with exactly one of @QueryParam/@PathParam/@MatrixParam/@CookieParam but its declared type is not String (e.g. int, Long, UUID). Hit during Quarkus build in CustomResourceProducersGenerator.generate().

Common situations: Declaring typed constructor params out of habit from field/method injection where automatic conversion to int/long works; expecting ParamConverter support which is intentionally not implemented here (see the TODO in the source).

Related errors


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