{"record":{"id":"ed755c20e44e6eaf","repo":"quarkusio/quarkus","slug":"onpongmessage-callback-must-return-unit-or-uni-vo","errorCode":null,"errorMessage":"@OnPongMessage callback must return Unit or Uni<Void>: ","messagePattern":"@OnPongMessage callback must return Unit 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":1104,"sourceCode":"        } else {\n            if (!callback.isReturnTypeVoid() && !isUniVoid(callback.returnType())) {\n                throw new WebSocketServerException(\n                        \"@OnPingMessage callback must return void or Uni<Void>: \" + callback.asString());\n            }\n        }\n        Type messageType = callback.argumentType(MessageCallbackArgument::isMessage);\n        if (messageType == null || !messageType.name().equals(WebSocketDotNames.BUFFER)) {\n            throw new WebSocketServerException(\n                    \"@OnPingMessage callback must accept exactly one message parameter of type io.vertx.core.buffer.Buffer: \"\n                            + callback.asString());\n        }\n    }\n\n    private void validateOnPongMessage(Callback callback) {\n        if (KotlinUtils.isKotlinMethod(callback.method)) {\n            if (!callback.isReturnTypeVoid() && !isUniVoid(callback.returnType())\n                    && !callback.isKotlinSuspendFunctionReturningUnit()) {\n                throw new WebSocketServerException(\n                        \"@OnPongMessage callback must return Unit or Uni<Void>: \" + callback.asString());\n            }\n        } else {\n            if (!callback.isReturnTypeVoid() && !isUniVoid(callback.returnType())) {\n                throw new WebSocketServerException(\n                        \"@OnPongMessage callback must return void or Uni<Void>: \" + callback.asString());\n            }\n        }\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)) {","sourceCodeStart":1086,"sourceCodeEnd":1122,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/extensions/websockets-next/deployment/src/main/java/io/quarkus/websockets/next/deployment/WebSocketProcessor.java#L1086-L1122","documentation":"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.","triggerScenarios":"A Kotlin method annotated @OnPongMessage returns a non-Unit, non-Uni<Void> type and is not a suspend function returning Unit.","commonSituations":"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.","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."],"exampleFix":"// before\n@OnPongMessage\nfun onPong(buffer: Buffer): Long { return elapsed }\n\n// after\n@OnPongMessage\nfun onPong(buffer: Buffer) { /* record elapsed in a field */ }","handlingStrategy":"validation","validationCode":"// Kotlin pre-check: @OnPongMessage must return Unit/Uni<Void> or suspend Unit\nfun checkPongCallback(m: KFunction<*>) {\n    val ret = m.returnType.classifier\n    check(ret == Unit::class || ret == Uni::class)\n        { \"@OnPongMessage must return Unit or Uni<Void>: ${m.name}\" }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["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"],"tags":["quarkus","websockets-next","kotlin","callback","build-time"],"backgroundTag":"invalid-callback-return-type","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"}