quarkusio/quarkus · error · java.lang.IllegalStateException

Route method that returns void must accept at least one…

Error message

Route method that returns void must accept at least one injectable parameter [method: %s, bean: %s]

What it means

Raised by ReactiveRoutesProcessor.validateRouteMethod when a @Route-annotated business method returns void but declares no parameters the framework can inject. A void route method cannot produce a response body, so it must either end the response itself via an injectable parameter (e.g. RoutingContext) or otherwise consume the request; the surrounding validation walks the method signature (params.isEmpty() with VOID return) and rejects methods that could neither reply nor observe anything.

Solutions

  1. Add an injectable parameter such as io.vertx.ext.web.RoutingContext to the route method so it can end the response
  2. Return a value (e.g. String, Uni<String>) from the method instead of void
  3. Annotate the method as a filter-style handler correctly (@Route with proper handler type) if that was intended
Defensive patterns

Strategy: validation

When it happens

Trigger: Thrown at extensions/reactive-routes/deployment/src/main/java/io/quarkus/vertx/web/deployment/ReactiveRoutesProcessor.java:535 when the library encounters an invalid state.

Common situations: See trigger scenarios.


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

Appendix: source

Thrown at extensions/reactive-routes/deployment/src/main/java/io/quarkus/vertx/web/deployment/ReactiveRoutesProcessor.java:535

        if (!method.returnType().kind().equals(Type.Kind.VOID)) {
            throw new IllegalStateException(
                    String.format("Route filter method must return void [method: %s, bean: %s]", method, bean));
        }
        List<Type> params = method.parameterTypes();
        if (params.size() != 1 || !params.get(0).name()
                .equals(DotNames.ROUTING_CONTEXT)) {
            throw new IllegalStateException(String.format(
                    "Route filter method must accept exactly one parameter of type %s: %s [method: %s, bean: %s]",
                    DotNames.ROUTING_CONTEXT, params, method, bean));
        }
    }

    private void validateRouteMethod(BeanInfo bean, MethodInfo method,
            TransformedAnnotationsBuildItem transformedAnnotations, IndexView index, AnnotationInstance routeAnnotation) {
        List<Type> params = method.parameterTypes();
        if (params.isEmpty()) {
            if (method.returnType().kind() == Kind.VOID && params.isEmpty()) {
                throw new IllegalStateException(String.format(
                        "Route method that returns void must accept at least one injectable parameter [method: %s, bean: %s]",
                        method, bean));
            }
        } else {
            AnnotationValue typeValue = routeAnnotation.value(VALUE_TYPE);
            Route.HandlerType handlerType = typeValue == null
                    ? Route.HandlerType.NORMAL
                    : Route.HandlerType.from(typeValue.asEnum());

            DotName returnTypeName = method.returnType().name();

            if ((returnTypeName.equals(DotNames.UNI)
                    || returnTypeName.equals(DotNames.MULTI)
                    || returnTypeName.equals(DotNames.COMPLETION_STAGE))
                    && method.returnType().kind() == Kind.CLASS) {
                throw new IllegalStateException(String.format(
                        "Route business method returning a Uni/Multi/CompletionStage must declare a type argument on the return type [method: %s, bean: %s]",
                        method, bean));

View on GitHub (pinned to e1c734241f)