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
- Change the constructor parameter type to String and convert it manually inside the constructor
- Move the parameter to the resource method signature where automatic type conversion is supported
- 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
- Always use String for JAX-RS-annotated constructor parameters; convert manually
- Use method parameters for automatic type conversion (int, long, etc.)
- Do not expect ParamConverter support in resource constructors
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
- Parameter: ${i} of the constructor of class '${resourceDotNa
- Unsupported type '${jaxRSAnnotationOfParam.name()}' used as
- A resource class cannot be simultaneously annotated with '@C
- Unable to load context type: ${typeParam}
- Unknown type '${type}' used as an annotation in constructor
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/8263b0a04511d468.
Report an issue: GitHub.