quarkusio/quarkus · error · IllegalStateException

Unsupported type '${jaxRSAnnotationOfParam.name()}' used as

Error message

Unsupported type '${jaxRSAnnotationOfParam.name()}' used as an annotation in constructor of class '${resourceDotName}'

What it means

The generator for resource classes with non-default constructors only knows how to map @QueryParam, @PathParam, @MatrixParam and @CookieParam constructor annotations to request values. A parameter annotated with any other JAX-RS annotation (e.g. @HeaderParam or @Context) reaches the mapping switch's else branch and throws this IllegalStateException.

Source

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

                            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 + "'");
                            }
                            String name = jaxRSAnnotationOfParam.value().asString(); // all the types we handle have the same annotation method
                            ctorParamData.add(new CtorParamData(customProducerParameterType, parameterType, name));
                        }
                    }
                }
                List<String> producerMethodParameterTypes = new ArrayList<>(ctor.parametersCount());
                for (CtorParamData ctorParamDatum : ctorParamData) {
                    if (ctorParamDatum.getCustomProducerParameterType() == CtorParamData.CustomProducerParameterType.OTHER) {
                        producerMethodParameterTypes.add(ctorParamDatum.getParameterType().name().toString());
                    }
                }

                String methodName = "producer_" + resourceDotName.withoutPackagePrefix()
                        + HashUtil.sha1(resourceDotName.toString());
                try (MethodCreator m = c.getMethodCreator(methodName, resourceDotName.toString(),
                        producerMethodParameterTypes.toArray(new String[0]))) {

View on GitHub (pinned to e1c734241f)

Solutions

  1. Restrict constructor parameter annotations to @QueryParam, @PathParam, @MatrixParam or @CookieParam
  2. Inject @HeaderParam/@Context values as method parameters or resource fields instead of constructor parameters
  3. Use @Inject of CDI beans (e.g. injected HttpHeaders/UriInfo providers) rather than JAX-RS @Context in the constructor

Example fix

// before
public MyResource(@HeaderParam("X-Tenant") String tenant) { ... }
// after
public MyResource() { ... }
public Response get(@HeaderParam("X-Tenant") String tenant) { ... }
Defensive patterns

Strategy: validation

Validate before calling

Set<String> supported = Set.of("jakarta.ws.rs.QueryParam","jakarta.ws.rs.PathParam","jakarta.ws.rs.MatrixParam","jakarta.ws.rs.CookieParam");
for (Parameter p : ctor.getParameters()) {
    for (Annotation a : p.getAnnotations()) {
        String n = a.annotationType().getName();
        if (n.startsWith("jakarta.ws.rs.") && !supported.contains(n))
            throw new IllegalStateException(n + " is not supported on resource constructor parameters");
    }
}

Prevention

When it happens

Trigger: A resource class has a non-default constructor with a parameter annotated with @HeaderParam, @Context, @FormParam or another annotation that is not one of the four supported parameter annotations, and the annotation is treated as a JAX-RS parameter annotation during the build.

Common situations: Injecting headers via constructor because query/path worked in the constructor before; trying to @Context-inject UriInfo or HttpHeaders in a resource constructor.

Related errors


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