quarkusio/quarkus · error · WebSocketException

Endpoint class may not be annotated with both @WebSocket and

Error message

Endpoint class may not be annotated with both @WebSocket and @WebSocketClient: 

What it means

A bean class annotated with @WebSocket is a server endpoint and with @WebSocketClient is a client endpoint; these are mutually exclusive. Quarkus rejects the deployment when both annotations are present because the endpoint's target (server vs client), path registration and lifecycle cannot be determined.

Source

Thrown at extensions/websockets-next/deployment/src/main/java/io/quarkus/websockets/next/deployment/WebSocketProcessor.java:344

            BuildProducer<WebSocketEndpointBuildItem> endpoints) {

        IndexView index = beanArchiveIndex.getIndex();

        // Collect WebSocket endpoints
        Map<String, DotName> serverIdToEndpoint = new HashMap<>();
        Map<String, DotName> serverPathToEndpoint = new HashMap<>();
        Map<String, DotName> clientIdToEndpoint = new HashMap<>();
        Map<String, DotName> clientPathToEndpoint = new HashMap<>();

        for (BeanInfo bean : beanDiscoveryFinished.beanStream().classBeans()) {
            ClassInfo beanClass = bean.getTarget().get().asClass();
            AnnotationInstance webSocketAnnotation = beanClass.annotation(WebSocketDotNames.WEB_SOCKET);
            AnnotationInstance webSocketClientAnnotation = beanClass.annotation(WebSocketDotNames.WEB_SOCKET_CLIENT);

            if (webSocketAnnotation == null && webSocketClientAnnotation == null) {
                continue;
            } else if (webSocketAnnotation != null && webSocketClientAnnotation != null) {
                throw new WebSocketException(
                        "Endpoint class may not be annotated with both @WebSocket and @WebSocketClient: " + beanClass);
            }
            String path;
            String id;
            AnnotationValue inboundProcessingMode;
            Target target;

            if (webSocketAnnotation != null) {
                target = Target.SERVER;
                path = getPath(webSocketAnnotation.value("path").asString());
                if (beanClass.nestingType() == NestingType.INNER) {
                    // Sub-websocket - merge the path from the enclosing classes
                    path = mergePath(getPathPrefix(index, beanClass.enclosingClass()), path);
                }
                DotName prevPath = serverPathToEndpoint.put(path, beanClass.name());
                if (prevPath != null) {
                    throw new WebSocketServerException(
                            String.format("Multiple endpoints [%s, %s] define the same path: %s", prevPath, beanClass, path));

View on GitHub (pinned to e1c734241f)

Solutions

  1. Remove either @WebSocket or @WebSocketClient from the class, keeping the one that matches its role
  2. Split the shared logic into two classes, one per annotation
  3. Check imports — io.quarkus.websockets.next.WebSocket vs WebSocketClient

Example fix

// before
@WebSocket(path = "/ws")
@WebSocketClient(path = "/client")
class MyWs {}
// after
@WebSocket(path = "/ws")
class MyWs {}
Defensive patterns

Strategy: validation

Validate before calling

// Compile-time-ish check in a shared base or unit test
void assertSingleWsAnnotation(Class<?> c) {
  boolean server = c.isAnnotationPresent(WebSocket.class);
  boolean client = c.isAnnotationPresent(WebSocketClient.class);
  if (server && client) throw new IllegalStateException(c + " has both @WebSocket and @WebSocketClient");
}

Prevention

When it happens

Trigger: Annotating the same class with both @WebSocket and @WebSocketClient, e.g. when sharing one class between a server and client test, or copy-pasting a client class and adding @WebSocket on top.

Common situations: Code sharing between server and client modules; accidental import of the wrong annotation causing a double annotation; refactoring an endpoint into a client and leaving the old annotation behind.

Related errors


AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05). Data as JSON: /api/errors/728394959a75fc04. Report an issue: GitHub.