{"record":{"id":"a14c42bb8f6dee43","repo":"quarkusio/quarkus","slug":"the-endpoint-must-declare-at-least-one-method-anno","errorCode":null,"errorMessage":"The endpoint must declare at least one method annotated with @OnTextMessage, @OnBinaryMessage, @OnPingMessage, @OnPongMessage or @OnOpen: ","messagePattern":"The endpoint must declare at least one method annotated with @OnTextMessage, @OnBinaryMessage, @OnPingMessage, @OnPongMessage or @OnOpen: ","errorType":"validation","errorClass":"WebSocketServerException","httpStatus":null,"severity":"error","filePath":"extensions/websockets-next/deployment/src/main/java/io/quarkus/websockets/next/deployment/WebSocketProcessor.java","lineNumber":419,"sourceCode":"\n            Callback onOpen = findCallback(target, beanArchiveIndex.getIndex(), bean, beanClass,\n                    WebSocketDotNames.ON_OPEN, callbackArguments, transformedAnnotations, path);\n            Callback onTextMessage = findCallback(target, beanArchiveIndex.getIndex(), bean, beanClass,\n                    WebSocketDotNames.ON_TEXT_MESSAGE, callbackArguments, transformedAnnotations, path);\n            Callback onBinaryMessage = findCallback(target, beanArchiveIndex.getIndex(), bean, beanClass,\n                    WebSocketDotNames.ON_BINARY_MESSAGE, callbackArguments, transformedAnnotations, path);\n            Callback onPingMessage = findCallback(target, beanArchiveIndex.getIndex(), bean, beanClass,\n                    WebSocketDotNames.ON_PING_MESSAGE, callbackArguments, transformedAnnotations, path,\n                    this::validateOnPingMessage);\n            Callback onPongMessage = findCallback(target, beanArchiveIndex.getIndex(), bean, beanClass,\n                    WebSocketDotNames.ON_PONG_MESSAGE, callbackArguments, transformedAnnotations, path,\n                    this::validateOnPongMessage);\n            Callback onClose = findCallback(target, beanArchiveIndex.getIndex(), bean, beanClass,\n                    WebSocketDotNames.ON_CLOSE, callbackArguments, transformedAnnotations, path,\n                    this::validateOnClose);\n            if (onOpen == null && onTextMessage == null && onBinaryMessage == null && onPingMessage == null\n                    && onPongMessage == null) {\n                throw new WebSocketServerException(\n                        \"The endpoint must declare at least one method annotated with @OnTextMessage, @OnBinaryMessage, @OnPingMessage, @OnPongMessage or @OnOpen: \"\n                                + beanClass);\n            }\n            if (onTextMessage != null) {\n                Type effectiveMessageType;\n                if (onTextMessage.isKotlinSuspendFunction()) {\n                    effectiveMessageType = onTextMessage.isReturnTypeUni()\n                            ? onTextMessage.returnType().asParameterizedType().arguments().get(0)\n                            : KotlinUtils.getKotlinSuspendMethodResult(onTextMessage.method);\n                } else if (onTextMessage.isReturnTypeUni() || onTextMessage.isReturnTypeMulti()) {\n                    effectiveMessageType = onTextMessage.returnType().asParameterizedType().arguments().get(0);\n                } else {\n                    effectiveMessageType = onTextMessage.returnType();\n                }\n                if (effectiveMessageType.kind() != Type.Kind.VOID && onTextMessage.getOutputCodec() == null) {\n                    reflectiveHierarchy\n                            .produce(ReflectiveHierarchyBuildItem.builder(effectiveMessageType).build());\n                }","sourceCodeStart":401,"sourceCodeEnd":437,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/extensions/websockets-next/deployment/src/main/java/io/quarkus/websockets/next/deployment/WebSocketProcessor.java#L401-L437","documentation":"An endpoint that has no @OnOpen, @OnTextMessage, @OnBinaryMessage, @OnPingMessage or @OnPongMessage method can never receive or process anything meaningful, so Quarkus rejects the deployment. @OnClose alone is not sufficient.","triggerScenarios":"Declaring a @WebSocket/@WebSocketClient class whose only callback is @OnClose (or which has no message callbacks at all).","commonSituations":"Starting with a skeleton endpoint before writing handlers; accidentally deleting/commenting-out the message methods during refactoring; wrong annotation imports (e.g. jakarta annotations not from io.quarkus.websockets.next) so the processor does not see them.","solutions":["Add at least one message callback, typically @OnTextMessage or @OnBinaryMessage","Or add @OnOpen if the endpoint only needs to react to connection opening","Verify the annotations used are from io.quarkus.websockets.next, not another package"],"exampleFix":"// before\n@WebSocket(path=\"/ws\")\nclass MyWs { @OnClose void close() {} }\n// after\n@WebSocket(path=\"/ws\")\nclass MyWs {\n  @OnTextMessage void onMessage(String msg) {}\n  @OnClose void close() {}\n}","handlingStrategy":"validation","validationCode":"@Test\nvoid endpointHasHandler(Class<?> endpoint) {\n  for (Method m : endpoint.getDeclaredMethods()) {\n    for (Class<?> ann : List.of(OnOpen.class, OnTextMessage.class, OnBinaryMessage.class,\n                                OnPingMessage.class, OnPongMessage.class)) {\n      if (m.isAnnotationPresent(ann)) return;\n    }\n  }\n  throw new AssertionError(endpoint + \" lacks @OnOpen or message handlers\");\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Start new endpoints from a template that includes @OnTextMessage","Verify annotation imports resolve to io.quarkus.websockets.next.*","Never leave a handler-only-@OnClose stub in committed code"],"tags":["websocket","build-time","missing-callback","annotation"],"backgroundTag":"required-handler-missing","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"}