{"record":{"id":"9b64147e492e4afd","repo":"quarkusio/quarkus","slug":"exactlyonce-on-method-methodname-cannot-combin","errorCode":null,"errorMessage":"@ExactlyOnce on method ${methodName} cannot combine @WithTransaction with a synchronous return type, use @Transactional instead","messagePattern":"@ExactlyOnce on method (.+?) cannot combine @WithTransaction with a synchronous return type, use @Transactional instead","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":194,"sourceCode":"                        \"@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) {\n                throw new IllegalArgumentException(\n                        \"@ExactlyOnce on method \" + methodName\n                                + \" cannot combine @WithTransaction with a synchronous return type\"\n                                + \", use @Transactional instead\");\n            }\n\n            if (method.hasAnnotation(DotNames.TRANSACTIONAL) && method.hasAnnotation(DotNames.WITH_TRANSACTION)) {\n                throw new IllegalArgumentException(\n                        \"@ExactlyOnce on method \" + methodName\n                                + \" cannot combine @Transactional with @WithTransaction\");\n            }\n\n            boolean isSuspend = method.parameterTypes().stream()\n                    .anyMatch(t -> t.name().equals(DotNames.CONTINUATION));\n            if (isSuspend) {\n                throw new IllegalArgumentException(\n                        \"@ExactlyOnce on method \" + methodName\n                                + \" does not support Kotlin suspend functions\");\n            }","sourceCodeStart":176,"sourceCodeEnd":212,"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#L176-L212","documentation":"@WithTransaction is only meaningful for reactive (Uni/Multi/CompletionStage) return types because it wraps the reactive pipeline in a transaction. When combined with a synchronous return type on an @ExactlyOnce method, the extension cannot apply it, so the build fails and the developer is pointed to @Transactional for synchronous CDI-managed transactions.","triggerScenarios":"An @ExactlyOnce method with a plain (non-reactive) return type is annotated with @io.smallrye.reactive.messaging.annotations.WithTransaction (or the SmallRye annotation).","commonSituations":"Mixing annotation styles when converting a synchronous processor to exactly-once, or cargo-culting @WithTransaction from reactive examples onto a sync method.","solutions":["Replace @WithTransaction with jakarta/javax @Transactional on the synchronous method.","Or make the method reactive (return Uni/CompletionStage) if you want @WithTransaction.","Remove @WithTransaction if no transactional semantics are required beyond the Kafka transaction."],"exampleFix":"// before\n@ExactlyOnce @WithTransaction\n@Incoming(\"in\") @Outgoing(\"out\")\npublic String process(String p) { ... }\n\n// after\n@ExactlyOnce @Transactional\n@Incoming(\"in\") @Outgoing(\"out\")\npublic String process(String p) { ... }","handlingStrategy":"validation","validationCode":"// sync method + @WithTransaction is invalid\nif (method.isAnnotationPresent(WithTransaction.class)\n        && !reactiveReturnType(method)) {\n    throw new IllegalStateException(\"Use @Transactional for synchronous return types\");\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Use @WithTransaction only on Uni/Multi/CompletionStage methods","Use @Transactional for synchronous methods","Pick one transaction style per codebase section to avoid mixing"],"tags":["kafka","reactive-messaging","exactly-once","transactions"],"backgroundTag":"with-transaction-sync-return","analyzedSha":"e1c734241f34c7919086ceb4c9262b4a58f6de44","analyzedAt":"2026-09-05T17:01:29.979Z","contentChangedAt":"2026-09-05T17:01:29.979Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}