{"record":{"id":"c73185ec3d908845","repo":"quarkusio/quarkus","slug":"exactlyonce-on-method-methodname-cannot-be-com","errorCode":null,"errorMessage":"@ExactlyOnce on method ${methodName} cannot be combined with @Blocking","messagePattern":"@ExactlyOnce on method (.+?) cannot be combined with @Blocking","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"extensions/smallrye-reactive-messaging-kafka/deployment/src/main/java/io/quarkus/smallrye/reactivemessaging/kafka/deployment/SmallRyeReactiveMessagingKafkaProcessor.java","lineNumber":175,"sourceCode":"            }\n\n            for (Type paramType : method.parameterTypes()) {\n                if (paramType.name().equals(DotNames.MESSAGE)) {\n                    throw new IllegalArgumentException(\n                            \"@ExactlyOnce on method \" + methodName\n                                    + \" does not support Message parameters, use payload types instead\");\n                }\n            }\n\n            if (method.returnType().name().equals(DotNames.VOID)\n                    || method.returnType().name().equals(VOID_BOXED)) {\n                throw new IllegalArgumentException(\n                        \"@ExactlyOnce on method \" + methodName\n                                + \" must return a value to produce to the outgoing channel\");\n            }\n\n            if (method.hasAnnotation(DotNames.BLOCKING) || method.hasAnnotation(DotNames.SMALLRYE_BLOCKING)) {\n                throw new IllegalArgumentException(\n                        \"@ExactlyOnce on method \" + methodName\n                                + \" cannot be combined with @Blocking\");\n            }\n\n            DotName returnTypeName = method.returnType().name();\n            boolean reactive = DotNames.UNI.equals(returnTypeName) || DotNames.MULTI.equals(returnTypeName)\n                    || DotNames.COMPLETION_STAGE.equals(returnTypeName);\n\n            if (reactive && method.returnType().kind() == Type.Kind.PARAMETERIZED_TYPE) {\n                DotName typeArg = method.returnType().asParameterizedType().arguments().get(0).name();\n                if (typeArg.equals(VOID_BOXED)) {\n                    throw new IllegalArgumentException(\n                            \"@ExactlyOnce on method \" + methodName\n                                    + \" must return a value to produce to the outgoing channel\");\n                }\n            }\n\n            if (method.hasAnnotation(DotNames.WITH_TRANSACTION) && !reactive) {","sourceCodeStart":157,"sourceCodeEnd":193,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/extensions/smallrye-reactive-messaging-kafka/deployment/src/main/java/io/quarkus/smallrye/reactivemessaging/kafka/deployment/SmallRyeReactiveMessagingKafkaProcessor.java#L157-L193","documentation":"@ExactlyOnce methods execute inside a Kafka transaction managed reactively by the extension; @Blocking would run the method on a worker thread and break the transactional/vert.x context the exactly-once invoker relies on. The deployment-time processor rejects the combination outright.","triggerScenarios":"A method annotated with both @ExactlyOnce and @Blocking (or io.smallrye.common.annotation.Blocking) is discovered during build.","commonSituations":"Adding @Blocking to an @ExactlyOnce processor to do JDBC or other blocking work, or inheriting @Blocking from a base class while enabling exactly-once.","solutions":["Remove @Blocking from the method.","Move blocking work inside the method body wrapped in Mutiny's runSubscription/emitOn if truly needed, keeping the method itself non-blocking.","Keep the return type reactive (Uni/Multi/CompletionStage) and avoid blocking annotations."],"exampleFix":"// before\n@ExactlyOnce @Blocking\n@Incoming(\"in\") @Outgoing(\"out\")\npublic String process(String p) { ... }\n\n// after\n@ExactlyOnce\n@Incoming(\"in\") @Outgoing(\"out\")\npublic String process(String p) { ... }","handlingStrategy":"validation","validationCode":"// before build: assert no @Blocking on @ExactlyOnce methods\nif (method.isAnnotationPresent(Blocking.class) || method.isAnnotationPresent(io.smallrye.common.annotation.Blocking.class)) {\n    throw new IllegalStateException(\"@Blocking conflicts with @ExactlyOnce\");\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep @ExactlyOnce methods non-blocking with reactive return types","Move blocking work inside the method body, not via @Blocking","Grep your codebase for @Blocking near @ExactlyOnce before upgrading"],"tags":["kafka","reactive-messaging","exactly-once","blocking"],"backgroundTag":"exactly-once-blocking-conflict","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"}