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

  1. Replace @WithTransaction with jakarta/javax @Transactional on the synchronous method.
  2. Or make the method reactive (return Uni/CompletionStage) if you want @WithTransaction.
  3. 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

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


AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05). Data as JSON: /api/errors/9b64147e492e4afd. Report an issue: GitHub.