quarkusio/quarkus · error · java.lang.IllegalStateException
Invalid combination - a reactive route cannot use @Blocking
Error message
Invalid combination - a reactive route cannot use @Blocking and use the type `failure` at the same time:
What it means
A reactive route business method annotated @Blocking cannot also declare handler type FAILURE: blocking failure handling is unsupported by the processor. When addAdditionalRoutes sees isBlocking() with HandlerType.FAILURE it throws IllegalStateException pointing at the offending method signature.
Source
Thrown at extensions/reactive-routes/deployment/src/main/java/io/quarkus/vertx/web/deployment/ReactiveRoutesProcessor.java:432
if (route.value(VALUE_CONSUMES) == null && baseConsumes != null) {
consumes = baseConsumes;
}
HandlerType handlerType = HandlerType.NORMAL;
if (routeHandlerType != null) {
handlerType = switch (routeHandlerType) {
case NORMAL -> HandlerType.NORMAL;
case BLOCKING -> HandlerType.BLOCKING;
case FAILURE -> HandlerType.FAILURE;
default -> throw new IllegalStateException("Unknown type " + routeHandlerType);
};
}
if (businessMethod.isBlocking()) {
if (handlerType == HandlerType.NORMAL) {
handlerType = HandlerType.BLOCKING;
} else if (handlerType == HandlerType.FAILURE) {
throw new IllegalStateException(
"Invalid combination - a reactive route cannot use @Blocking and use the type `failure` at the same time: "
+ businessMethod.getMethod().toString());
}
}
if (routeHandler == null) {
String handlerClass = generateHandler(
new HandlerDescriptor(businessMethod.getMethod(), beanValidationAnnotations.orElse(null),
handlerType == HandlerType.FAILURE, produces),
businessMethod.getBean(), businessMethod.getMethod(), gizmo, transformedAnnotations,
route, reflectiveHierarchy, produces.length > 0 ? produces[0] : null,
validatorAvailable, index);
reflectiveClasses
.produce(ReflectiveClassBuildItem.builder(handlerClass).build());
routeHandler = recorder.createHandler(handlerClass);
routeHandlers.put(routeString, routeHandler);
}
View on GitHub (pinned to e1c734241f)
Solutions
- Remove @Blocking from the method annotated with type = RouteHandlerType.FAILURE
- Or remove type = FAILURE so the method is treated as a normal blocking route
- If blocking work is needed on failure, keep the failure route non-blocking and delegate to a worker thread (e.g. Vertx.executeBlocking or a CDI bean offloaded with @Blocking elsewhere)
Example fix
// before
@Blocking
@Route(path = "/err", type = RouteHandlerType.FAILURE)
public void handle(RoutingContext rc) { ... }
// after
@Route(path = "/err", type = RouteHandlerType.FAILURE)
public void handle(RoutingContext rc) { /* non-blocking only */ } Defensive patterns
Strategy: validation
Validate before calling
if (method.isAnnotatedWith(Blocking.class)
&& route.type() == RouteHandlerType.FAILURE) {
throw new IllegalStateException(
method + " cannot be @Blocking and type=FAILURE");
} Prevention
- Never add @Blocking to type=FAILURE routes
- Keep failure handlers non-blocking; offload heavy work to worker beans
- Code-review route annotations after refactors
When it happens
Trigger: A method combining @Blocking (or a blocking method signature, e.g. returning non-reactive types that force blocking) with @Route(type = RouteHandlerType.FAILURE).
Common situations: Adding @Blocking to an existing failure route to do blocking error logging; copy-pasting a failure handler from a non-blocking route; annotations added by refactoring tools.
Related errors
- Unknown type
- Attempting a blocking read on io thread
- Failed to find any non-blocking provider for startup actions
- Blocking gRPC client call made from the event loop. If the c
- You have attempted to perform a blocking operation on a IO t
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/a08f3dcefe29e97e.
Report an issue: GitHub.