quarkusio/quarkus · error · WebSocketServerException
@OnPongMessage callback must return Unit or Uni<Void>:
Error message
@OnPongMessage callback must return Unit or Uni<Void>:
What it means
Thrown by WebSocketProcessor's @OnPongMessage validation (the Kotlin branch of the ping/pong callback checks) when a Kotlin pong callback does not return Unit or Uni<Void>. Pong callbacks mirror ping callbacks: they are fire-and-ack only, so a return value of any other type fails build-time validation, with the callback's string representation appended for identification.
Source
Thrown at extensions/websockets-next/deployment/src/main/java/io/quarkus/websockets/next/deployment/WebSocketProcessor.java:1104
} else {
if (!callback.isReturnTypeVoid() && !isUniVoid(callback.returnType())) {
throw new WebSocketServerException(
"@OnPingMessage callback must return void or Uni<Void>: " + callback.asString());
}
}
Type messageType = callback.argumentType(MessageCallbackArgument::isMessage);
if (messageType == null || !messageType.name().equals(WebSocketDotNames.BUFFER)) {
throw new WebSocketServerException(
"@OnPingMessage callback must accept exactly one message parameter of type io.vertx.core.buffer.Buffer: "
+ callback.asString());
}
}
private void validateOnPongMessage(Callback callback) {
if (KotlinUtils.isKotlinMethod(callback.method)) {
if (!callback.isReturnTypeVoid() && !isUniVoid(callback.returnType())
&& !callback.isKotlinSuspendFunctionReturningUnit()) {
throw new WebSocketServerException(
"@OnPongMessage callback must return Unit or Uni<Void>: " + callback.asString());
}
} else {
if (!callback.isReturnTypeVoid() && !isUniVoid(callback.returnType())) {
throw new WebSocketServerException(
"@OnPongMessage callback must return void or Uni<Void>: " + callback.asString());
}
}
Type messageType = callback.argumentType(MessageCallbackArgument::isMessage);
if (messageType == null || !messageType.name().equals(WebSocketDotNames.BUFFER)) {
throw new WebSocketServerException(
"@OnPongMessage callback must accept exactly one message parameter of type io.vertx.core.buffer.Buffer: "
+ callback.asString());
}
}
private void validateOnClose(Callback callback) {
if (KotlinUtils.isKotlinMethod(callback.method)) {View on GitHub (pinned to e1c734241f)
Solutions
- Change the return type to Unit (or make the function suspend returning Unit).
- Or return io.smallrye.mutiny.Uni<Void>.
- Record any pong statistics via fields or logging inside the handler instead of returning them.
Example fix
// before
@OnPongMessage
fun onPong(buffer: Buffer): Long { return elapsed }
// after
@OnPongMessage
fun onPong(buffer: Buffer) { /* record elapsed in a field */ } Defensive patterns
Strategy: validation
Validate before calling
// Kotlin pre-check: @OnPongMessage must return Unit/Uni<Void> or suspend Unit
fun checkPongCallback(m: KFunction<*>) {
val ret = m.returnType.classifier
check(ret == Unit::class || ret == Uni::class)
{ "@OnPongMessage must return Unit or Uni<Void>: ${m.name}" }
} Prevention
- Return Unit from pong handlers; record stats via fields/logging
- Mirror the ping handler's return contract
- Avoid returning latency/measurement values directly
- Lint callback signatures in CI for Kotlin endpoints
When it happens
Trigger: A Kotlin method annotated @OnPongMessage returns a non-Unit, non-Uni<Void> type and is not a suspend function returning Unit.
Common situations: Returning measurement/latency values from the pong handler; mirroring a Java callback that accidentally returned a value; confusion between suspend Unit and explicit return values in Kotlin.
Related errors
- @OnPingMessage callback must return Unit or Uni<Void>:
- @OnPingMessage callback must return void or Uni<Void>:
- @OnPingMessage callback must accept exactly one message para
- Something went wrong during parameter type resolution - expe
- Unable to inject @%s callback parameter '%s' declared on %s:
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/ed755c20e44e6eaf.
Report an issue: GitHub.