{"record":{"id":"3c6d78ca76174764","repo":"quarkusio/quarkus","slug":"the-blocking-nonblocking-and-runonvirtualthrea","errorCode":null,"errorMessage":"The @Blocking, @NonBlocking and @RunOnVirtualThread annotations may only be used on \"entrypoint\" methods (methods invoked by various frameworks in Quarkus)\nUsing the @Blocking, @NonBlocking and @RunOnVirtualThread annotations on methods that can only be invoked by application code is invalid","messagePattern":"The @Blocking, @NonBlocking and @RunOnVirtualThread annotations may only be used on \"entrypoint\" methods \\(methods invoked by various frameworks in Quarkus\\)\nUsing the @Blocking, @NonBlocking and @RunOnVirtualThread annotations on methods that can only be invoked by application code is invalid","errorType":"validation","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"core/deployment/src/main/java/io/quarkus/deployment/execannotations/ExecutionModelAnnotationsProcessor.java","lineNumber":53,"sourceCode":"\n        if (config.detectionMode() == ExecutionModelAnnotationsConfig.Mode.DISABLED) {\n            return;\n        }\n\n        StringBuilder message = new StringBuilder(\"\\n\");\n        doCheck(message, index.getIndex(), predicates, BLOCKING);\n        doCheck(message, index.getIndex(), predicates, NON_BLOCKING);\n        doCheck(message, index.getIndex(), predicates, RUN_ON_VIRTUAL_THREAD);\n\n        if (message.length() > 1) {\n            message.append(\"The @Blocking, @NonBlocking and @RunOnVirtualThread annotations may only be used \"\n                    + \"on \\\"entrypoint\\\" methods (methods invoked by various frameworks in Quarkus)\\n\");\n            message.append(\"Using the @Blocking, @NonBlocking and @RunOnVirtualThread annotations on methods \"\n                    + \"that can only be invoked by application code is invalid\");\n            if (config.detectionMode() == ExecutionModelAnnotationsConfig.Mode.WARN) {\n                log.warn(message);\n            } else {\n                throw new IllegalStateException(message.toString());\n            }\n        }\n    }\n\n    private void doCheck(StringBuilder message, IndexView index,\n            List<ExecutionModelAnnotationsAllowedBuildItem> predicates, DotName annotationName) {\n\n        List<String> badMethods = new ArrayList<>();\n        for (AnnotationInstance annotation : index.getAnnotations(annotationName)) {\n            // these annotations may be put on classes too, but we'll ignore that for now\n            if (annotation.target() != null && annotation.target().kind() == AnnotationTarget.Kind.METHOD) {\n                MethodInfo method = annotation.target().asMethod();\n                boolean allowed = false;\n                for (ExecutionModelAnnotationsAllowedBuildItem predicate : predicates) {\n                    if (predicate.matches(method)) {\n                        allowed = true;\n                        break;\n                    }","sourceCodeStart":35,"sourceCodeEnd":71,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/core/deployment/src/main/java/io/quarkus/deployment/execannotations/ExecutionModelAnnotationsProcessor.java#L35-L71","documentation":"Quarkus's execution-model annotation processor verifies that @Blocking, @NonBlocking and @RunOnVirtualThread appear only on entrypoint methods (those invoked by frameworks: CDI observers, HTTP endpoints, scheduled tasks, etc.). If it finds them on methods only callable from application code, it logs a failure message; in strict mode it throws IllegalStateException.","triggerScenarios":"quarkus-execution-model-annotation build step 'check' during augmentation finds the annotations on a private/internal method or a method invoked solely by other application code, with quarkus.execution-model-detection-mode=strict (default).","commonSituations":"Developer annotates a helper method with @Blocking or @RunOnVirtualThread intending to influence the caller; annotation inherited onto internal methods via a class-level/inheritable placement mistake; refactor moves an annotated entrypoint method into internal-only code.","solutions":["Move the annotation to the actual entrypoint (resource method, @Scheduled method, observer) and let the execution model propagate to helpers via context","Remove the annotation from non-entrypoint methods — it has no effect there anyway","Set quarkus.execution-model-detection-mode=warn temporarily to downgrade to a warning while migrating","Split logic: keep an entrypoint method annotated, call unannotated internal methods from it"],"exampleFix":"// before\n@RunOnVirtualThread\nvoid helper() { ... } // only called from application code\n// after\nvoid helper() { ... } // annotate only the entrypoint, e.g. the JAX-RS method or @Scheduled method","handlingStrategy":"validation","validationCode":"// Build-time check habit: annotate only methods that Quarkus invokes itself\n// Entry points: JAX-RS resource methods, @Scheduled, CDI observers (@Observes), messaging consumers\nif (!isQuarkusEntryPoint(method)) throw new IllegalStateException(\"@Blocking/@NonBlocking/@RunOnVirtualThread only on entrypoints: \" + method);","typeGuard":"static boolean isExecutionModelAnnotation(AnnotationInstance a) {\n    return a.name().equals(DotName.createSimple(\"io.smallrye.common.annotation.Blocking\"))\n        || a.name().equals(DotName.createSimple(\"io.smallrye.common.annotation.NonBlocking\"))\n        || a.name().equals(DotName.createSimple(\"io.smallrye.common.annotation.RunOnVirtualThread\"));\n}","tryCatchPattern":"try {\n    quarkusBuild();\n} catch (IllegalStateException e) {\n    if (e.getMessage().contains(\"entrypoint\\\" methods\")) {\n        // locate the annotated non-entrypoint method named in the message and remove/move the annotation\n    }\n    throw e;\n}","preventionTips":["Annotate only framework-invoked methods; execution model propagates transitively to helpers","Search the codebase for stray @Blocking/@RunOnVirtualThread on private/internal methods in code review","Use quarkus.execution-model-detection-mode=warn while migrating to catch violations without failing the build"],"tags":["annotations","build-time","cdi"],"backgroundTag":"annotation-placement-invalid","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"}