quarkusio/quarkus · error · DeploymentException

Class has no fields. Parameters containers are only…

Error message

Class %s has no fields. Parameters containers are only supported if they have at least one annotated field.

What it means

When a @BeanParam class has no field extractors and requires no injection, ServerEndpointIndexer checks its declared methods; if there are none, the class is completely empty, so deployment fails with this DeploymentException. Parameter containers must have at least one annotated field to be meaningful.

Solutions

  1. Add at least one field annotated with a REST parameter annotation (@QueryParam, @HeaderParam, @PathParam, etc.).
  2. Remove the @BeanParam parameter if no parameters are needed.
  3. If annotations sit on methods, move them onto fields (see the companion error) — an empty class can never be a valid container.

Example fix

// before
class UserParams {}

// after
class UserParams {
    @QueryParam("name")
    String name;
}
Defensive patterns

Strategy: validation

Validate before calling

if (UserParams.class.getDeclaredFields().length == 0
    && UserParams.class.getDeclaredMethods().length == 0) {
    throw new IllegalStateException("@BeanParam class must declare at least one annotated field");
}

Prevention

When it happens

Trigger: Using an empty POJO as a @BeanParam parameter, e.g. get(@BeanParam MyParams p) where MyParams has no fields and no methods.

Common situations: Placeholder/scaffolding bean param classes left empty; refactoring removed all fields but kept the @BeanParam usage; copying a resource signature without the params class contents.

Related errors


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

Appendix: source

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

                    return intMethod;
                }
            }
        }
        return null;
    }

    @Override
    protected boolean handleBeanParam(ClassInfo actualEndpointInfo, Type paramType, MethodParameter[] methodParameters, int i,
            Set<String> fileFormNames) {
        ClassInfo beanParamClassInfo = index.getClassByName(paramType.name());
        InjectableBean injectableBean = scanInjectableBean(beanParamClassInfo,
                actualEndpointInfo,
                existingConverters, additionalReaders, injectableBeans, hasRuntimeConverters);
        if ((injectableBean.getFieldExtractorsCount() == 0) && !injectableBean.isInjectionRequired()) {
            long declaredMethodsCount = beanParamClassInfo.methods().stream()
                    .filter(m -> !m.name().equals("<init>") && !m.name().equals("<clinit>")).count();
            if (declaredMethodsCount == 0) {
                throw new DeploymentException(String.format(
                        "Class %s has no fields. Parameters containers are only supported if they have at least one annotated field.",
                        beanParamClassInfo.name()));
            } else {
                throw new DeploymentException(String.format("No annotations found on fields at '%s'. "
                        + "Annotations like `@QueryParam` should be used in fields, not in methods.",
                        beanParamClassInfo.name()));
            }

        }
        fileFormNames.addAll(injectableBean.getFileFormNames());
        return injectableBean.isFormParamRequired();
    }

    @Override
    protected boolean doesMethodHaveBlockingSignature(MethodInfo info) {
        for (var i : methodScanners) {
            if (i.isMethodSignatureAsync(info)) {
                return false;

View on GitHub (pinned to e1c734241f)