quarkusio/quarkus · error · WebSocketServerException
@OnClose callback must return Unit or Uni<Void>:
Error message
@OnClose callback must return Unit or Uni<Void>:
What it means
For Kotlin @OnClose callbacks, the method must return Unit (including suspend functions returning Unit) or Uni<Void>. A close callback performs shutdown side effects and must not return a value. When isKotlinMethod detects a Kotlin method whose return type is none of these, the build throws WebSocketServerException.
Source
Thrown at extensions/websockets-next/deployment/src/main/java/io/quarkus/websockets/next/deployment/WebSocketProcessor.java:1125
} 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)) {
if (!callback.isReturnTypeVoid() && !isUniVoid(callback.returnType())
&& !callback.isKotlinSuspendFunctionReturningUnit()) {
throw new WebSocketServerException(
"@OnClose callback must return Unit or Uni<Void>: " + callback.asString());
}
} else {
if (!callback.isReturnTypeVoid() && !isUniVoid(callback.returnType())) {
throw new WebSocketServerException(
"@OnClose callback must return void or Uni<Void>: " + callback.asString());
}
}
}
/**
* The generated endpoint class looks like:
*
* <pre>
* public class Echo_WebSocketEndpoint extends WebSocketEndpointBase {
*
* public WebSocket.ExecutionMode executionMode() {
* return WebSocket.ExecutionMode.SERIAL;View on GitHub (pinned to e1c734241f)
Solutions
- Make the Kotlin @OnClose function return Unit (either explicitly or by having no meaningful return)
- If suspending, declare it as a suspend fun returning Unit
- Alternatively return Uni<Void> from Mutiny for reactive close handling
Example fix
// before (Kotlin)
@OnClose
fun onClose(): String { return "closed" }
// after (Kotlin)
@OnClose
fun onClose() { /* cleanup */ } Defensive patterns
Strategy: validation
Validate before calling
// Kotlin check
if (m.isAnnotationPresent(OnClose::class.java)) {
require(m.returnType == Unit::class.java || isUniVoid(m)) { "@OnClose must return Unit or Uni<Void>" }
} Prevention
- Write close handlers as `fun onClose()` or `suspend fun onClose()`
- Avoid returning Job/Deferred from lifecycle callbacks
- Use Uni<Void> for reactive cleanup
When it happens
Trigger: A Kotlin method annotated @OnClose that returns a non-Unit type such as String, Boolean, or Job, and is not a suspend function returning Unit nor a Uni<Void> returner.
Common situations: Kotlin developer forgets the trailing Unit return convention when converting a Java void callback; returning a coroutine Job from the close handler; refactoring an @OnClose method to return a result.
Related errors
- @OnPingMessage callback must return Unit or Uni<Void>:
- @OnPongMessage callback must return Unit or Uni<Void>:
- @OnPongMessage callback must return void or Uni<Void>:
- @OnPongMessage callback must accept exactly one message para
- @OnClose callback must return void or Uni<Void>:
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/bd876b021f08852f.
Report an issue: GitHub.