quarkusio/quarkus · error · java.lang.IllegalStateException

Route filter method must return void [method: %s, bean: %s]

Error message

Route filter method must return void [method: %s, bean: %s]

What it means

Route filter methods (@RouteFilter) must return void because they work by mutating the RoutingContext/continuing the chain, not by returning a value. validateRouteFilterMethod throws IllegalStateException during build if a filter method declares a non-void return type.

Source

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

                    priorityValue != null ? priorityValue.asInt() : RouteFilter.DEFAULT_PRIORITY));
        }

        detectConflictingRoutes(matchers);
    }

    @BuildStep
    AutoAddScopeBuildItem autoAddScope() {
        return AutoAddScopeBuildItem.builder()
                .containsAnnotations(DotNames.ROUTE,
                        DotNames.ROUTES,
                        DotNames.ROUTE_FILTER)
                .defaultScope(BuiltinScope.SINGLETON)
                .reason("Found route handler business methods").build();
    }

    private void validateRouteFilterMethod(BeanInfo bean, MethodInfo method) {
        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]",

View on GitHub (pinned to e1c734241f)

Solutions

  1. Change the @RouteFilter method return type to void
  2. If a value must be produced, store it in the RoutingContext via rc.put(...) instead of returning it
  3. Rename the method so IDE quick-fixes don't reintroduce a return type

Example fix

// before
@RouteFilter(100)
public String myFilter(RoutingContext rc) { ... }
// after
@RouteFilter(100)
public void myFilter(RoutingContext rc) { rc.next(); }
Defensive patterns

Strategy: validation

Validate before calling

Method m = bean.getClass().getMethod("myFilter", RoutingContext.class);
if (m.isAnnotationPresent(RouteFilter.class)
        && m.getReturnType() != void.class) {
    throw new IllegalStateException("@RouteFilter must return void");
}

Type guard

boolean isValidRouteFilter(Method m) {
    return m.getReturnType() == void.class
        && m.getParameterCount() == 1
        && m.getParameterTypes()[0] == RoutingContext.class;
}

Prevention

When it happens

Trigger: Annotating a @RouteFilter method that returns a value (e.g. String, Response, Uni) instead of void.

Common situations: Returning a value from a filter by habit from JAX-RS filters; converting an endpoint method into a filter while keeping its return type; forgetting to change the signature when adding @RouteFilter.

Related errors


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