quarkusio/quarkus · error · IllegalArgumentException
@ExactlyOnce on method ${methodName} cannot combine @WithTra
Error message
@ExactlyOnce on method ${methodName} cannot combine @WithTransaction with a synchronous return type, use @Transactional instead What it means
@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.
Source
Thrown at extensions/smallrye-reactive-messaging-kafka/deployment/src/main/java/io/quarkus/smallrye/reactivemessaging/kafka/deployment/SmallRyeReactiveMessagingKafkaProcessor.java:194
"@ExactlyOnce on method " + methodName
+ " cannot be combined with @Blocking");
}
DotName returnTypeName = method.returnType().name();
boolean reactive = DotNames.UNI.equals(returnTypeName) || DotNames.MULTI.equals(returnTypeName)
|| DotNames.COMPLETION_STAGE.equals(returnTypeName);
if (reactive && method.returnType().kind() == Type.Kind.PARAMETERIZED_TYPE) {
DotName typeArg = method.returnType().asParameterizedType().arguments().get(0).name();
if (typeArg.equals(VOID_BOXED)) {
throw new IllegalArgumentException(
"@ExactlyOnce on method " + methodName
+ " must return a value to produce to the outgoing channel");
}
}
if (method.hasAnnotation(DotNames.WITH_TRANSACTION) && !reactive) {
throw new IllegalArgumentException(
"@ExactlyOnce on method " + methodName
+ " cannot combine @WithTransaction with a synchronous return type"
+ ", use @Transactional instead");
}
if (method.hasAnnotation(DotNames.TRANSACTIONAL) && method.hasAnnotation(DotNames.WITH_TRANSACTION)) {
throw new IllegalArgumentException(
"@ExactlyOnce on method " + methodName
+ " cannot combine @Transactional with @WithTransaction");
}
boolean isSuspend = method.parameterTypes().stream()
.anyMatch(t -> t.name().equals(DotNames.CONTINUATION));
if (isSuspend) {
throw new IllegalArgumentException(
"@ExactlyOnce on method " + methodName
+ " does not support Kotlin suspend functions");
}View on GitHub (pinned to e1c734241f)
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.
Example fix
// before
@ExactlyOnce @WithTransaction
@Incoming("in") @Outgoing("out")
public String process(String p) { ... }
// after
@ExactlyOnce @Transactional
@Incoming("in") @Outgoing("out")
public String process(String p) { ... } Defensive patterns
Strategy: validation
Validate before calling
// sync method + @WithTransaction is invalid
if (method.isAnnotationPresent(WithTransaction.class)
&& !reactiveReturnType(method)) {
throw new IllegalStateException("Use @Transactional for synchronous return types");
} Prevention
- Use @WithTransaction only on Uni/Multi/CompletionStage methods
- Use @Transactional for synchronous methods
- Pick one transaction style per codebase section to avoid mixing
When it happens
Trigger: An @ExactlyOnce method with a plain (non-reactive) return type is annotated with @io.smallrye.reactive.messaging.annotations.WithTransaction (or the SmallRye annotation).
Common situations: Mixing annotation styles when converting a synchronous processor to exactly-once, or cargo-culting @WithTransaction from reactive examples onto a sync method.
Related errors
- @ExactlyOnce on method ${methodName} cannot combine @Transac
- @ExactlyOnce on method ${methodName} requires both @Incoming
- @ExactlyOnce on method ${methodName} must return a value to
- @ExactlyOnce on method ${methodName} cannot be combined with
- @ExactlyOnce on method ${methodName} does not support Kotlin
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/9b64147e492e4afd.
Report an issue: GitHub.