quarkusio/quarkus · error · WebSocketServerException
Multiple endpoints [%s, %s] define the same endpoint id: %s
Error message
Multiple endpoints [%s, %s] define the same endpoint id: %s
What it means
Every server endpoint has an id, taken from @WebSocket(endpointId=...) or defaulting to the class name. Ids must be unique because WebSocketConnection.ConnectionOpenOptions/endpoints are looked up by id; a collision fails deployment with WebSocketServerException.
Source
Thrown at extensions/websockets-next/deployment/src/main/java/io/quarkus/websockets/next/deployment/WebSocketProcessor.java:372
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));
}
AnnotationValue endpointIdValue = webSocketAnnotation.value("endpointId");
if (endpointIdValue == null) {
id = beanClass.name().toString();
} else {
id = endpointIdValue.asString();
}
DotName prevId = serverIdToEndpoint.put(id, beanClass.name());
if (prevId != null) {
throw new WebSocketServerException(
String.format("Multiple endpoints [%s, %s] define the same endpoint id: %s", prevId, beanClass,
id));
}
inboundProcessingMode = webSocketAnnotation.value("inboundProcessingMode");
} else {
target = Target.CLIENT;
path = getPath(webSocketClientAnnotation.value("path").asString());
DotName prevPath = clientPathToEndpoint.put(path, beanClass.name());
if (prevPath != null) {
throw new WebSocketServerException(
String.format("Multiple client endpoints [%s, %s] define the same path: %s", prevPath, beanClass,
path));
}
AnnotationValue clientIdValue = webSocketClientAnnotation.value("clientId");
if (clientIdValue == null) {
id = beanClass.name().toString();
} else {
id = clientIdValue.asString();View on GitHub (pinned to e1c734241f)
Solutions
- Change the endpointId value on one of the endpoints
- Remove the explicit endpointId so the unique class name is used
- Search the codebase for the duplicated endpointId string to find both occurrences
Example fix
// before
@WebSocket(path="/a", endpointId="chat") class A {}
@WebSocket(path="/b", endpointId="chat") class B {}
// after
@WebSocket(path="/b", endpointId="chat-admin") class B {} Defensive patterns
Strategy: validation
Validate before calling
@Test
void endpointIdsUnique() {
Set<String> ids = new HashSet<>();
for (Class<?> c : allEndpoints) {
WebSocket ws = c.getAnnotation(WebSocket.class);
String id = ws.endpointId().isEmpty() ? c.getName() : ws.endpointId();
if (!ids.add(id)) throw new AssertionError("Duplicate endpointId: " + id);
}
} Prevention
- Only set endpointId when you actually need a custom id; default FQCN ids never collide
- Reference ids via a shared constants class instead of string literals
- Update all connection-open call sites when renaming ids
When it happens
Trigger: Two @WebSocket classes both declaring the same endpointId value, or one explicitly set equal to another class's implicit id (the fully-qualified class name).
Common situations: Copying an endpoint with its endpointId attribute; refactoring class names so a chosen endpointId now collides; generating endpoints where ids are templated incorrectly.
Related errors
- Multiple client endpoints [%s, %s] define the same endpoint
- Multiple global @OnError callbacks may not accept the same e
- Multiple checked templates exist for the template path %s:
- Only a single instance of '${annotation}' is allowed per RES
- Detected two @PermissionChecker annotations with same value
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/62c8ae6d8136cfc6.
Report an issue: GitHub.