{"record":{"id":"105b095c3a3771c2","repo":"quarkusio/quarkus","slug":"onclose-callback-must-return-void-or-uni-void","errorCode":null,"errorMessage":"@OnClose callback must return void or Uni<Void>: ","messagePattern":"@OnClose callback must return void or Uni<Void>: ","errorType":"validation","errorClass":"WebSocketServerException","httpStatus":null,"severity":"error","filePath":"extensions/websockets-next/deployment/src/main/java/io/quarkus/websockets/next/deployment/WebSocketProcessor.java","lineNumber":1130,"sourceCode":"        }\n        Type messageType = callback.argumentType(MessageCallbackArgument::isMessage);\n        if (messageType == null || !messageType.name().equals(WebSocketDotNames.BUFFER)) {\n            throw new WebSocketServerException(\n                    \"@OnPongMessage callback must accept exactly one message parameter of type io.vertx.core.buffer.Buffer: \"\n                            + callback.asString());\n        }\n    }\n\n    private void validateOnClose(Callback callback) {\n        if (KotlinUtils.isKotlinMethod(callback.method)) {\n            if (!callback.isReturnTypeVoid() && !isUniVoid(callback.returnType())\n                    && !callback.isKotlinSuspendFunctionReturningUnit()) {\n                throw new WebSocketServerException(\n                        \"@OnClose callback must return Unit or Uni<Void>: \" + callback.asString());\n            }\n        } else {\n            if (!callback.isReturnTypeVoid() && !isUniVoid(callback.returnType())) {\n                throw new WebSocketServerException(\n                        \"@OnClose callback must return void or Uni<Void>: \" + callback.asString());\n            }\n        }\n    }\n\n    /**\n     * The generated endpoint class looks like:\n     *\n     * <pre>\n     * public class Echo_WebSocketEndpoint extends WebSocketEndpointBase {\n     *\n     *     public WebSocket.ExecutionMode executionMode() {\n     *         return WebSocket.ExecutionMode.SERIAL;\n     *     }\n     *\n     *     public Echo_WebSocketEndpoint(WebSocketConnection connection, Codecs codecs,\n     *             WebSocketRuntimeConfig config, ContextSupport contextSupport, SecuritySupport securitySupport) {\n     *         super(connection, codecs, config, contextSupport, securitySupport);","sourceCodeStart":1112,"sourceCodeEnd":1148,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/extensions/websockets-next/deployment/src/main/java/io/quarkus/websockets/next/deployment/WebSocketProcessor.java#L1112-L1148","documentation":"For non-Kotlin @OnClose callbacks, the method must return void or Uni<Void>. Close callbacks are invoked on connection close and their return value is discarded, so any other return type fails the build-time signature validation with WebSocketServerException.","triggerScenarios":"A Java @OnClose method returning e.g. String, int, CompletionStage<Void>, io.smallrye.mutiny.Uni<String>, or any POJO.","commonSituations":"Returning CompletionStage instead of Mutiny Uni (not accepted); returning a status/result object; copy-pasting from @OnTextMessage handlers that return message replies.","solutions":["Change the return type to void","For async cleanup, return Uni<Void> and complete with null","If you need CompletionStage semantics, wrap it: Uni.createFrom().completionStage(...)"],"exampleFix":"// before\n@OnClose\nCompletionStage<Void> onClose() { return done; }\n\n// after\n@OnClose\nUni<Void> onClose() { return Uni.createFrom().completionStage(() -> done); }","handlingStrategy":"validation","validationCode":"for (Method m : MyWebSocket.class.getDeclaredMethods()) {\n    if (m.isAnnotationPresent(OnClose.class)) {\n        boolean ok = m.getReturnType().equals(void.class) || Uni.class.isAssignableFrom(m.getReturnType());\n        if (!ok) throw new IllegalStateException(m + \" must return void or Uni<Void>\");\n    }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Default to void for @OnClose","Remember CompletionStage is not accepted — use Mutiny Uni<Void>","Run quarkus:dev to catch signature errors immediately"],"tags":["quarkus","websockets-next","build-time-validation","callback-signature"],"backgroundTag":"callback-return-type-mismatch","analyzedSha":"e1c734241f34c7919086ceb4c9262b4a58f6de44","analyzedAt":"2026-09-05T17:01:29.979Z","contentChangedAt":"2026-09-05T17:01:29.979Z","schemaVersion":2},"datasetVersion":"2026-09-12T22:17:10.623Z"}