quarkusio/quarkus · error · DeploymentException

Body parameters (or non-annotated fields) are not allowed fo

Error message

Body parameters (or non-annotated fields) are not allowed for records. Make sure to annotate your record components with @Rest* or @*Param or that they can be injected as context objects.

What it means

Records used as parameters containers (@BeanParam or record endpoint parameters) must have every component resolvable to a REST parameter or context object. An unannotated component defaults to ParameterType.BODY, which is disallowed for records, so a DeploymentException is thrown.

Source

Thrown at independent-projects/resteasy-reactive/server/processor/src/main/java/org/jboss/resteasy/reactive/server/processor/ServerEndpointIndexer.java:405

        // records do not have field injection, we use their constructor, so field rules do not apply
        boolean applyFieldRules = !currentClassInfo.isRecord();
        // Keep build deterministic by using field order.
        for (FieldInfo field : currentClassInfo.fieldsInDeclarationOrder()) {
            // We don't do any injection in static fields
            if (Modifier.isStatic(field.flags())) {
                continue;
            }
            Map<DotName, AnnotationInstance> annotations = new HashMap<>();
            for (AnnotationInstance i : field.annotations()) {
                annotations.put(i.name(), i);
            }
            ServerIndexedParameter result = extractParameterInfo(currentClassInfo, actualEndpointInfo, null, existingConverters,
                    additionalReaders,
                    annotations, field.type(), "%s", new Object[] { field }, applyFieldRules, hasRuntimeConverters,
                    // We don't support annotation-less path params in injectable beans: only annotations
                    Collections.emptySet(), field.name(), EMPTY_STRING_ARRAY, new HashMap<>());
            if (currentClassInfo.isRecord() && result.getType() == ParameterType.BODY) {
                throw new DeploymentException(
                        "Body parameters (or non-annotated fields) are not allowed for records. Make sure to annotate your record components with @Rest* or @*Param or that they can be injected as context objects.");
            }
            if ((result.getType() != null) && (result.getType() != ParameterType.BEAN)) {
                //BODY means no annotation, so for fields not injectable
                fieldExtractors.put(field, result);
            }
            if (result.getType() == ParameterType.BEAN) {
                beanParamFields.put(field, result);
                // transform the bean param
                // FIXME: pretty sure this doesn't work with generics
                ClassInfo beanParamClassInfo = index.getClassByName(field.type().name());
                InjectableBean injectableBean = scanInjectableBean(beanParamClassInfo, actualEndpointInfo,
                        existingConverters, additionalReaders, injectableBeans, hasRuntimeConverters);
                // inherit form param requirement from field
                if (injectableBean.isFormParamRequired()) {
                    currentInjectableBean.setFormParamRequired(true);
                }
            } else if (result.getType() == ParameterType.FORM) {

View on GitHub (pinned to e1c734241f)

Solutions

  1. Annotate the component with @Rest* / @*Param (@QueryParam, @HeaderParam, @RestForm, etc.).
  2. If it is a context object (UriInfo, HttpHeaders, etc.) verify the type is auto-injectable — otherwise annotate or remove it.
  3. Remove the component; for request bodies use a plain class or a dedicated body parameter.

Example fix

// before
record UserSearch(String name, @QueryParam("limit") int limit) {}

// after
record UserSearch(@QueryParam("name") String name, @QueryParam("limit") int limit) {}
Defensive patterns

Strategy: validation

Validate before calling

for (RecordComponent rc : UserSearch.class.getRecordComponents()) {
    boolean annotated = java.util.Arrays.stream(rc.getAnnotations())
        .anyMatch(a -> a.annotationType().getName().startsWith("org.jboss.resteasy.reactive")
                   || a.annotationType().getName().endsWith("Param"));
    if (!annotated) throw new IllegalStateException("Component " + rc.getName() + " needs a @Rest*/@*Param annotation");
}

Prevention

When it happens

Trigger: record MyParams(@QueryParam("q") String q, String unannotated) used as an endpoint parameter or @BeanParam — the unannotated component triggers the error.

Common situations: Adding a new record component without an annotation; using records as body/DTO holders assuming automatic binding; migrating from classes where an unannotated field meant body.

Related errors


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