quarkusio/quarkus · error · IllegalArgumentException
@ExactlyOnce on method ${methodName} requires at least one p
Error message
@ExactlyOnce on method ${methodName} requires at least one parameter What it means
An @ExactlyOnce Kafka processing method must accept at least one parameter, because exactly-once processing needs the incoming payload/Message to forward to the @Outgoing stream. A zero-parameter method fails the deployment build.
Source
Thrown at extensions/smallrye-reactive-messaging-kafka/deployment/src/main/java/io/quarkus/smallrye/reactivemessaging/kafka/deployment/SmallRyeReactiveMessagingKafkaProcessor.java:155
DefaultSerdeDiscoveryState discoveryState = new DefaultSerdeDiscoveryState(combinedIndex.getIndex());
for (AnnotationInstance annotation : combinedIndex.getIndex().getAnnotations(DotNames.EXACTLY_ONCE)) {
if (annotation.target().kind() != AnnotationTarget.Kind.METHOD) {
continue;
}
MethodInfo method = annotation.target().asMethod();
String methodName = method.declaringClass().name() + "#" + method.name();
AnnotationInstance incoming = method.annotation(DotNames.INCOMING);
AnnotationInstance outgoing = method.annotation(DotNames.OUTGOING);
if (incoming == null || outgoing == null) {
throw new IllegalArgumentException(
"@ExactlyOnce on method " + methodName + " requires both @Incoming and @Outgoing annotations");
}
if (method.parametersCount() == 0) {
throw new IllegalArgumentException(
"@ExactlyOnce on method " + methodName + " requires at least one parameter");
}
for (Type paramType : method.parameterTypes()) {
if (paramType.name().equals(DotNames.MESSAGE)) {
throw new IllegalArgumentException(
"@ExactlyOnce on method " + methodName
+ " does not support Message parameters, use payload types instead");
}
}
if (method.returnType().name().equals(DotNames.VOID)
|| method.returnType().name().equals(VOID_BOXED)) {
throw new IllegalArgumentException(
"@ExactlyOnce on method " + methodName
+ " must return a value to produce to the outgoing channel");
}
View on GitHub (pinned to e1c734241f)
Solutions
- Add the incoming payload parameter (e.g. String m or the specific payload type).
- Use a Message<T> payload? No — Message parameters are rejected; use raw payload type instead (see related error).
- Remove @ExactlyOnce if the method is meant to be a pure producer.
Example fix
// before
@Incoming("in") @Outgoing("out") @ExactlyOnce
String process() { return "x"; }
// after
@Incoming("in") @Outgoing("out") @ExactlyOnce
String process(String payload) { return transform(payload); } Defensive patterns
Strategy: validation
Validate before calling
fun validateExactlyOnceSignature(paramCount: Int, hasExactlyOnce: Boolean): Boolean =
!hasExactlyOnce || paramCount >= 1 Prevention
- Always consume the incoming payload parameter in @ExactlyOnce methods.
- Do not strip 'unused' parameters from processing methods.
- Rely on IDE annotation-inspection to flag empty-signature processors.
When it happens
Trigger: @ExactlyOnce on a method with no parameters (e.g. a supplier-style method alongside @Incoming+@Outgoing).
Common situations: Converting a @Pollable/supplier method to @ExactlyOnce; cleaning up 'unused' parameters that were actually required.
Related errors
- @ExactlyOnce on method ${methodName} requires both @Incoming
- @ExactlyOnce on method ${methodName} does not support Messag
- Unknown cache type:
- Unable to determine the value type for '" + cacheName + "' R
- Unsupported type: " + type
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/d7f7fcebf4c8acea.
Report an issue: GitHub.