quarkusio/quarkus · error · ConfigurationException
The method `${method}` is using `@RunOnVirtualThread` but ex
Error message
The method `${method}` is using `@RunOnVirtualThread` but explicitly set as `@Blocking(ordered = true)` What it means
Quarkus Reactive Messaging validates mediator method configuration at build time. A method annotated with @RunOnVirtualThread must not simultaneously be declared @Blocking(ordered = true), because ordered blocking forces a serialized worker pool that conflicts with virtual thread execution semantics. The build fails with a ConfigurationException.
Source
Thrown at extensions/smallrye-reactive-messaging/deployment/src/main/java/io/quarkus/smallrye/reactivemessaging/deployment/QuarkusMediatorConfigurationUtil.java:248
}
}
AnnotationInstance blockingAnnotation = methodInfo.annotation(BLOCKING);
AnnotationInstance smallryeBlockingAnnotation = methodInfo.annotation(SMALLRYE_BLOCKING);
AnnotationInstance transactionalAnnotation = methodInfo.annotation(TRANSACTIONAL);
AnnotationInstance runOnVirtualThreadAnnotation = methodInfo.annotation(RUN_ON_VIRTUAL_THREAD);
// IF @RunOnVirtualThread is used on the declaring class, it forces all @Blocking method to be run on virtual threads.
AnnotationInstance runOnVirtualThreadClassAnnotation = methodInfo.declaringClass()
.declaredAnnotation(RUN_ON_VIRTUAL_THREAD);
if (blockingAnnotation != null || smallryeBlockingAnnotation != null || transactionalAnnotation != null
|| runOnVirtualThreadAnnotation != null) {
mediatorConfigurationSupport.validateBlocking(validationOutput);
configuration.setBlocking(true);
if (blockingAnnotation != null) {
AnnotationValue ordered = blockingAnnotation.value("ordered");
if (runOnVirtualThreadAnnotation != null || runOnVirtualThreadClassAnnotation != null) {
if (ordered != null && ordered.asBoolean()) {
throw new ConfigurationException(
"The method `" + methodInfo.name()
+ "` is using `@RunOnVirtualThread` but explicitly set as `@Blocking(ordered = true)`");
}
configuration.setBlockingExecutionOrdered(false);
configuration.setWorkerPoolName(QuarkusWorkerPoolRegistry.DEFAULT_VIRTUAL_THREAD_WORKER);
} else {
configuration.setBlockingExecutionOrdered(ordered == null || ordered.asBoolean());
}
String poolName;
if (blockingAnnotation.value() != null &&
!(poolName = blockingAnnotation.value().asString()).equals(Blocking.DEFAULT_WORKER_POOL)) {
configuration.setWorkerPoolName(poolName);
}
} else if (runOnVirtualThreadAnnotation != null || runOnVirtualThreadClassAnnotation != null) {
configuration.setBlockingExecutionOrdered(false);
configuration.setWorkerPoolName(QuarkusWorkerPoolRegistry.DEFAULT_VIRTUAL_THREAD_WORKER);
} else {
configuration.setBlockingExecutionOrdered(true);View on GitHub (pinned to e1c734241f)
Solutions
- Remove @Blocking(ordered = true) — keep @Blocking (unordered) if blocking execution is needed; Quarkus will run it on the virtual thread worker
- Drop @RunOnVirtualThread if you explicitly need ordered blocking on the default worker pool
- Use plain @Blocking (no ordered attribute) when combining with @RunOnVirtualThread
Example fix
// before
@Incoming("in")
@RunOnVirtualThread
@Blocking(ordered = true)
void process(String msg) { ... }
// after
@Incoming("in")
@RunOnVirtualThread
@Blocking
void process(String msg) { ... } Defensive patterns
Strategy: validation
Validate before calling
// at build/test time, assert the combination is absent
if (method.hasAnnotation(DotNames.RUN_ON_VIRTUAL_THREAD)
&& method.hasAnnotation(DotNames.BLOCKING)
&& method.annotation(DotNames.BLOCKING).value("ordered") != null
&& method.annotation(DotNames.BLOCKING).value("ordered").asBoolean()) {
throw new IllegalStateException("@RunOnVirtualThread + @Blocking(ordered=true)");
} Prevention
- Never combine @RunOnVirtualThread with @Blocking(ordered = true)
- Use plain @Blocking (unordered) when mixing with virtual threads
- Review mediator method annotations after migrating to virtual threads
When it happens
Trigger: Combining @Incoming (or @Outgoing) processing with both @RunOnVirtualThread and @Blocking(ordered = true) on the same method; inheriting @RunOnVirtualThread from the class while adding ordered @Blocking on the method.
Common situations: Migrating to virtual threads and keeping the old ordered-blocking annotation; copy-pasting @Blocking(ordered = true) from another mediator method.
Related errors
- The method `${method}` is using `@Keyed` but is not annotate
- The method `${method}` is using `@Keyed` but the annotated p
- @ExactlyOnce on method ${methodName} must return a value to
- An event consumer business method that cannot use @RunOnVirt
- ${exceptionMsgSupplier.get()} (nonBlocking/virtual-thread an
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/2271049e1493f634.
Report an issue: GitHub.