quarkusio/quarkus · error · WebSocketException
@%s callback must not accept a message parameter; found %s:
Error message
@%s callback must not accept a message parameter; found %s: %s
What it means
Callbacks that do not accept messages (acceptsMessage() is false, e.g. @OnOpen, @OnClose, @OnPongMessage per their rules) must not declare any message parameters. If one or more MessageCallbackArgument parameters are found, the build fails naming the annotation, the count, and the callback.
Source
Thrown at extensions/websockets-next/deployment/src/main/java/io/quarkus/websockets/next/deployment/WebSocketProcessor.java:1916
return null;
} else if (annotations.size() == 1) {
AnnotationInstance annotation = annotations.get(0);
MethodInfo method = annotation.target().asMethod();
Callback callback = new Callback(target, annotation, bean, method,
executionModel(method, transformedAnnotations), callbackArguments, transformedAnnotations,
endpointPath, index);
long messageArguments = callback.arguments.stream().filter(ca -> ca instanceof MessageCallbackArgument).count();
if (callback.acceptsMessage()) {
if (messageArguments > 1) {
throw new WebSocketException(
String.format("@%s callback may accept at most 1 message parameter; found %s: %s",
DotNames.simpleName(callback.annotation.name()),
messageArguments,
callback.asString()));
}
} else {
if (messageArguments != 0) {
throw new WebSocketException(
String.format("@%s callback must not accept a message parameter; found %s: %s",
DotNames.simpleName(callback.annotation.name()),
messageArguments,
callback.asString()));
}
}
if (target == Target.CLIENT && callback.broadcast()) {
throw new WebSocketClientException(
String.format("@%s callback declared on a client endpoint must not broadcast messages: %s",
DotNames.simpleName(callback.annotation.name()),
callback.asString()));
}
if (validator != null) {
validator.accept(callback);
}
return callback;
}
throw new WebSocketException(View on GitHub (pinned to e1c734241f)
Solutions
- Remove the message parameter from the @OnOpen/@OnClose callback
- Store the needed data in connection-scoped state (e.g. a request-scoped bean or WebSocketConnection attribute) instead
- If message data is genuinely needed at that lifecycle point, use an appropriate @OnTextMessage/@OnBinaryMessage callback
Example fix
// before
@OnOpen
void onOpen(String firstMessage) {}
// after
@OnOpen
void onOpen(WebSocketConnection conn) {}
Defensive patterns
Strategy: validation
Validate before calling
for (Method m : MyWebSocket.class.getDeclaredMethods()) {
var a = m.getAnnotation(OnOpen.class);
if (a != null || m.isAnnotationPresent(OnClose.class)) {
boolean hasMessageParam = Arrays.stream(m.getParameterTypes())
.anyMatch(t -> t == String.class || t == byte[].class
|| t.getName().equals("io.vertx.core.buffer.Buffer"));
if (hasMessageParam) throw new IllegalStateException(m + " must not accept a message parameter");
}
} Prevention
- Lifecycle callbacks (@OnOpen/@OnClose) take only connection/context parameters
- Remove leftover message params when switching annotations
- Carry state via connection-scoped beans, not callback arguments
When it happens
Trigger: Adding a message-typed parameter (String, Buffer, DTO) to an @OnOpen or @OnClose method; annotation not matched by acceptsMessage() due to its kind while its signature looks like a message handler.
Common situations: Developer expects to receive the last message in onOpen/onClose; copy-paste from an @OnTextMessage handler; leftover message parameter after changing the annotation.
Related errors
- @OnPongMessage callback must return void or Uni<Void>:
- @OnPongMessage callback must accept exactly one message para
- @OnClose callback must return void or Uni<Void>:
- @OnError callback must accept exactly one error parameter; f
- @%s callback may accept at most 1 message parameter; found %
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/88bcb164d5757ed4.
Report an issue: GitHub.