quarkusio/quarkus · error · IllegalStateException

Unable to create route handler: " + handlerClassName

Error message

Unable to create route handler: " + handlerClassName

What it means

VertxWebRecorder.createHandler loads a handler class generated at build time and instantiates it reflectively at startup. If the class cannot be loaded or instantiated (missing, wrong name, or no no-arg constructor), an IllegalStateException wrapping the reflective cause is thrown.

Source

Thrown at extensions/reactive-routes/runtime/src/main/java/io/quarkus/vertx/web/runtime/VertxWebRecorder.java:50

            VertxHttpBuildTimeConfig httpBuildTimeConfig) {
        this.httpConfig = httpConfig;
        this.httpBuildTimeConfig = httpBuildTimeConfig;
    }

    @SuppressWarnings("unchecked")
    public Handler<RoutingContext> createHandler(String handlerClassName) {
        try {
            ClassLoader cl = Thread.currentThread().getContextClassLoader();
            if (cl == null) {
                cl = VertxWebRecorder.class.getClassLoader();
            }
            Class<? extends Handler<RoutingContext>> handlerClazz = (Class<? extends Handler<RoutingContext>>) cl
                    .loadClass(handlerClassName);
            RouteHandler handler = (RouteHandler) handlerClazz.getDeclaredConstructor().newInstance();
            return handler;
        } catch (InstantiationException | IllegalAccessException | ClassNotFoundException | NoSuchMethodException
                | InvocationTargetException e) {
            throw new IllegalStateException("Unable to create route handler: " + handlerClassName, e);
        }
    }

    public Handler<RoutingContext> runOnVirtualThread(Handler<RoutingContext> routeHandler) {
        return new VirtualThreadsRouteHandler(routeHandler);
    }

    public Handler<RoutingContext> compressRouteHandler(Handler<RoutingContext> routeHandler, HttpCompression compression) {
        if (httpBuildTimeConfig.enableCompression()) {
            return new HttpCompressionHandler(routeHandler, compression,
                    compression == HttpCompression.UNDEFINED
                            ? Set.copyOf(httpBuildTimeConfig.compressMediaTypes().orElse(List.of()))
                            : Set.of());
        } else {
            return routeHandler;
        }
    }

View on GitHub (pinned to e1c734241f)

Solutions

  1. Run a clean rebuild (./mvnw clean install) so generated handler classes match the current code.
  2. Verify the handlerClassName corresponds to a class generated by ReactiveRoutesProcessor and the extension versions are aligned.
  3. For native builds, ensure the generated handler class is registered for reflection (Quarkus normally does this automatically; check for custom exclude patterns in native configuration).
Defensive patterns

Strategy: try-catch

Validate before calling

// validate the class exists and is instantiable before use
Class<?> c = Class.forName(handlerClassName);
if (!Handler.class.isAssignableFrom(c) || c.getDeclaredConstructors()[0].getParameterCount() != 0)
    throw new IllegalStateException("Invalid handler class: " + handlerClassName);

Try / catch

try {
    return recorder.createHandler(name);
} catch (IllegalStateException e) {
    log.error("Handler {} missing; rebuilding? cause={}", name, e.getCause());
    throw e;
}

Prevention

When it happens

Trigger: Calling VertxWebRecorder.createHandler with a handlerClassName that was not generated by ReactiveRoutesProcessor, refers to a class removed/renamed between builds, or has no public no-arg constructor.

Common situations: Stale build artifacts after refactoring generated handler names; mixing versions of quarkus-vertx-http and quarkus-reactive-routes; custom code calling the recorder directly with a mistyped class name; native-image builds where the class was not registered for reflection.

Related errors


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