{"record":{"id":"2271049e1493f634","repo":"quarkusio/quarkus","slug":"the-method-method-is-using-runonvirtualthre","errorCode":null,"errorMessage":"The method `${method}` is using `@RunOnVirtualThread` but explicitly set as `@Blocking(ordered = true)`","messagePattern":"The method `(.+?)` is using `@RunOnVirtualThread` but explicitly set as `@Blocking\\(ordered = true\\)`","errorType":"validation","errorClass":"ConfigurationException","httpStatus":null,"severity":"error","filePath":"extensions/smallrye-reactive-messaging/deployment/src/main/java/io/quarkus/smallrye/reactivemessaging/deployment/QuarkusMediatorConfigurationUtil.java","lineNumber":248,"sourceCode":"            }\n        }\n\n        AnnotationInstance blockingAnnotation = methodInfo.annotation(BLOCKING);\n        AnnotationInstance smallryeBlockingAnnotation = methodInfo.annotation(SMALLRYE_BLOCKING);\n        AnnotationInstance transactionalAnnotation = methodInfo.annotation(TRANSACTIONAL);\n        AnnotationInstance runOnVirtualThreadAnnotation = methodInfo.annotation(RUN_ON_VIRTUAL_THREAD);\n        // IF @RunOnVirtualThread is used on the declaring class, it forces all @Blocking method to be run on virtual threads.\n        AnnotationInstance runOnVirtualThreadClassAnnotation = methodInfo.declaringClass()\n                .declaredAnnotation(RUN_ON_VIRTUAL_THREAD);\n        if (blockingAnnotation != null || smallryeBlockingAnnotation != null || transactionalAnnotation != null\n                || runOnVirtualThreadAnnotation != null) {\n            mediatorConfigurationSupport.validateBlocking(validationOutput);\n            configuration.setBlocking(true);\n            if (blockingAnnotation != null) {\n                AnnotationValue ordered = blockingAnnotation.value(\"ordered\");\n                if (runOnVirtualThreadAnnotation != null || runOnVirtualThreadClassAnnotation != null) {\n                    if (ordered != null && ordered.asBoolean()) {\n                        throw new ConfigurationException(\n                                \"The method `\" + methodInfo.name()\n                                        + \"` is using `@RunOnVirtualThread` but explicitly set as `@Blocking(ordered = true)`\");\n                    }\n                    configuration.setBlockingExecutionOrdered(false);\n                    configuration.setWorkerPoolName(QuarkusWorkerPoolRegistry.DEFAULT_VIRTUAL_THREAD_WORKER);\n                } else {\n                    configuration.setBlockingExecutionOrdered(ordered == null || ordered.asBoolean());\n                }\n                String poolName;\n                if (blockingAnnotation.value() != null &&\n                        !(poolName = blockingAnnotation.value().asString()).equals(Blocking.DEFAULT_WORKER_POOL)) {\n                    configuration.setWorkerPoolName(poolName);\n                }\n            } else if (runOnVirtualThreadAnnotation != null || runOnVirtualThreadClassAnnotation != null) {\n                configuration.setBlockingExecutionOrdered(false);\n                configuration.setWorkerPoolName(QuarkusWorkerPoolRegistry.DEFAULT_VIRTUAL_THREAD_WORKER);\n            } else {\n                configuration.setBlockingExecutionOrdered(true);","sourceCodeStart":230,"sourceCodeEnd":266,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/extensions/smallrye-reactive-messaging/deployment/src/main/java/io/quarkus/smallrye/reactivemessaging/deployment/QuarkusMediatorConfigurationUtil.java#L230-L266","documentation":"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.","triggerScenarios":"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.","commonSituations":"Migrating to virtual threads and keeping the old ordered-blocking annotation; copy-pasting @Blocking(ordered = true) from another mediator method.","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"],"exampleFix":"// before\n@Incoming(\"in\")\n@RunOnVirtualThread\n@Blocking(ordered = true)\nvoid process(String msg) { ... }\n// after\n@Incoming(\"in\")\n@RunOnVirtualThread\n@Blocking\nvoid process(String msg) { ... }","handlingStrategy":"validation","validationCode":"// at build/test time, assert the combination is absent\nif (method.hasAnnotation(DotNames.RUN_ON_VIRTUAL_THREAD)\n    && method.hasAnnotation(DotNames.BLOCKING)\n    && method.annotation(DotNames.BLOCKING).value(\"ordered\") != null\n    && method.annotation(DotNames.BLOCKING).value(\"ordered\").asBoolean()) {\n    throw new IllegalStateException(\"@RunOnVirtualThread + @Blocking(ordered=true)\");\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["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"],"tags":["reactive-messaging","virtual-threads","build-time-validation"],"backgroundTag":"conflicting-annotations","analyzedSha":"e1c734241f34c7919086ceb4c9262b4a58f6de44","analyzedAt":"2026-09-05T17:01:29.979Z","contentChangedAt":"2026-09-05T17:01:29.979Z","schemaVersion":2},"datasetVersion":"2026-09-12T22:17:10.623Z"}