quarkusio/quarkus · error · DeploymentException

Resource classes that use field injection for REST parameter

Error message

Resource classes that use field injection for REST parameters can only be @RequestScoped. Offending class is ${clazz.name()}

What it means

During CDI processing, Quarkus automatically adds @RequestScoped to resource classes that use field injection of REST parameters — unless the class already declares a different builtin scope. If a resource that needs field injection carries an explicit scope other than @RequestScoped, deployment aborts with this DeploymentException (same rule as the indexer-side check, enforced while synthesizing scopes).

Source

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

                .getRequestScopedResources();

        additionalBeanBuildItemBuildProducer.produce(new io.quarkus.arc.deployment.AnnotationsTransformerBuildItem(
                AnnotationTransformation.builder().whenDeclaration(
                        new Predicate<>() {
                            @Override
                            public boolean test(Declaration declaration) {
                                return declaration.kind() == AnnotationTarget.Kind.CLASS;
                            }
                        }).transform(new Consumer<>() {
                            @Override
                            public void accept(AnnotationTransformation.TransformationContext context) {
                                if (context.declaration().kind() == AnnotationTarget.Kind.CLASS) {
                                    ClassInfo clazz = context.declaration().asClass();
                                    if (requestScopedResources.contains(clazz.name())) {
                                        BuiltinScope builtinScope = BuiltinScope.from(clazz);
                                        if (builtinScope != null) {
                                            if (builtinScope.getName() != BuiltinScope.REQUEST.getName()) {
                                                throw new DeploymentException(
                                                        "Resource classes that use field injection for REST parameters can only be @RequestScoped. Offending class is "
                                                                + clazz.name());
                                            } else {
                                                // nothing to do as @RequestScoped was already present
                                            }
                                        } else if (!resourceScanningResultBuildItem.get().getResult().getPossibleSubResources()
                                                .containsKey(clazz.name())) {
                                            // no @RequestScoped for Sub Resources, since they might have a constructor
                                            // not compatible with CDI. User must explicitly mark as RequestScoped
                                            context.add(RequestScoped.class);
                                        }
                                    }
                                }
                            }
                        })));
    }

    @BuildStep

View on GitHub (pinned to e1c734241f)

Solutions

  1. Change the resource scope annotation to @RequestScoped
  2. Move REST parameter injection from fields to resource method parameters, allowing any scope
  3. Use constructor injection instead of field injection

Example fix

// before
@Singleton
@Path("/items")
public class ItemResource {
    @PathParam("id")
    String id;
}
// after
@RequestScoped
@Path("/items")
public class ItemResource {
    @PathParam("id")
    String id;
}
Defensive patterns

Strategy: validation

Validate before calling

if (Arrays.stream(clazz.getDeclaredFields())
        .anyMatch(f -> Arrays.stream(f.getAnnotations())
                .anyMatch(a -> a.annotationType().getName().startsWith("jakarta.ws.rs.")))) {
    if (clazz.isAnnotationPresent(jakarta.inject.Singleton.class)
            || clazz.isAnnotationPresent(jakarta.enterprise.context.ApplicationScoped.class))
        throw new IllegalStateException(clazz + " needs field injection: use @RequestScoped or method params");
}

Prevention

When it happens

Trigger: A resource class found in requestScopedResources (i.e. it uses field injection of REST parameters) has an explicit @Singleton/@ApplicationScoped/other builtin scope annotation; the synthetic-scope CDI build step detects the mismatch and fails the build.

Common situations: Annotating resources @ApplicationScoped while using @QueryParam fields; a parent class or stereotype pulling in a different scope; adding field injection later to an already-scoped resource.

Related errors


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