{"record":{"id":"3f36b1a9f9f8023c","repo":"quarkusio/quarkus","slug":"method-of-class-is-considered-a-non-blocking","errorCode":null,"errorMessage":"Method '' of class '' is considered a non blocking method. @RunOnVirtualThread can only be used on  methods considered blocking","messagePattern":"Method '' of class '' is considered a non blocking method\\. @RunOnVirtualThread can only be used on  methods considered blocking","errorType":"validation","errorClass":"DeploymentException","httpStatus":null,"severity":"error","filePath":"independent-projects/resteasy-reactive/common/processor/src/main/java/org/jboss/resteasy/reactive/common/processor/EndpointIndexer.java","lineNumber":894,"sourceCode":"            value = annotation.value().asString();\n        }\n\n        return value;\n    }\n\n    private boolean isRunOnVirtualThread(MethodInfo info, boolean blocking, BlockingDefault defaultValue) {\n        Map.Entry<AnnotationTarget, AnnotationInstance> runOnVirtualThreadAnnotation = getInheritableAnnotation(info,\n                RUN_ON_VIRTUAL_THREAD);\n        Map.Entry<AnnotationTarget, AnnotationInstance> blockingAnnotation = getInheritableAnnotation(info, BLOCKING);\n        Map.Entry<AnnotationTarget, AnnotationInstance> nonBlockingAnnotation = getInheritableAnnotation(info, NON_BLOCKING);\n\n        if (runOnVirtualThreadAnnotation != null) {\n            if (!blocking) {\n                if (blockingAnnotation != null) {\n                    return false;\n                }\n                if (nonBlockingAnnotation != null) {\n                    throw new DeploymentException(\n                            \"Method '\" + info.name() + \"' of class '\" + info.declaringClass().name()\n                                    + \"' is considered a non blocking method. @RunOnVirtualThread can only be used on \" +\n                                    \" methods considered blocking\");\n                }\n                return true;\n            } else {\n                return true;\n            }\n        } else {\n            if (blockingAnnotation != null) {\n                return false;\n            } else {\n                return defaultValue == BlockingDefault.RUN_ON_VIRTUAL_THREAD;\n            }\n        }\n    }\n\n    private boolean isBlocking(MethodInfo info, BlockingDefault defaultValue) {","sourceCodeStart":876,"sourceCodeEnd":912,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/independent-projects/resteasy-reactive/common/processor/src/main/java/org/jboss/resteasy/reactive/common/processor/EndpointIndexer.java#L876-L912","documentation":"@RunOnVirtualThread is only meaningful for methods RESTEasy Reactive considers blocking (it indicates they should run on a virtual thread instead of a worker thread). When a method already carries an explicit @NonBlocking annotation, combining it with @RunOnVirtualThread is a contradiction and the deployment fails with this DeploymentException.","triggerScenarios":"A resource method annotated with both @RunOnVirtualThread and @NonBlocking is deployed; the class-level/method-level blocking resolution marks the method non-blocking via an explicit @NonBlocking annotation while @RunOnVirtualThread is also present.","commonSituations":"Copy-pasting threading annotations between reactive endpoints; adding @RunOnVirtualThread to an endpoint that was previously made non-blocking for performance; mixing annotation-driven threading styles on the same class.","solutions":["Remove @NonBlocking from the method so it is treated as blocking and can run on a virtual thread","Or remove @RunOnVirtualThread if the method is genuinely reactive/non-blocking","Keep @RunOnVirtualThread only on methods doing blocking work where virtual-thread execution is desired"],"exampleFix":"// before\n@RunOnVirtualThread\n@NonBlocking\npublic String get() { ... }\n// after\n@RunOnVirtualThread\npublic String get() { ... }","handlingStrategy":"validation","validationCode":"Method m = MyResource.class.getMethod(\"get\");\nif (m.isAnnotationPresent(RunOnVirtualThread.class) && m.isAnnotationPresent(NonBlocking.class)) {\n    throw new IllegalStateException(\"@RunOnVirtualThread conflicts with @NonBlocking on \" + m);\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Use @RunOnVirtualThread only for blocking workloads you want on virtual threads","Never combine @RunOnVirtualThread with @NonBlocking on the same method","Keep threading annotations consistent per class; annotate methods individually when they differ","Add a unit test scanning resource classes for contradictory threading annotations"],"tags":["quarkus","resteasy-reactive","virtual-threads","nonblocking","deployment"],"backgroundTag":"runonvirtualthread-misuse","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"}