{"record":{"id":"9af46c8aec7208e3","repo":"perwendel/spark","slug":"websocket-handler-must-implement-websocketlistene","errorCode":null,"errorMessage":"WebSocket handler must implement 'WebSocketListener' or be annotated as '@WebSocket'","messagePattern":"WebSocket handler must implement 'WebSocketListener' or be annotated as '@WebSocket'","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"src/main/java/spark/embeddedserver/jetty/websocket/WebSocketHandlerWrapper.java","lineNumber":22,"sourceCode":"import org.eclipse.jetty.websocket.api.annotations.WebSocket;\n\n/**\n * A wrapper for web socket handler classes/instances.\n */\npublic interface WebSocketHandlerWrapper {\n    \n    /**\n     * Gets the actual handler - if necessary, instantiating an object.\n     * \n     * @return The handler instance.\n     */\n    Object getHandler();\n    \n    static void validateHandlerClass(Class<?> handlerClass) {\n        boolean valid = WebSocketListener.class.isAssignableFrom(handlerClass)\n                || handlerClass.isAnnotationPresent(WebSocket.class);\n        if (!valid) {\n            throw new IllegalArgumentException(\n                    \"WebSocket handler must implement 'WebSocketListener' or be annotated as '@WebSocket'\");\n        }\n    }\n\n}\n","sourceCodeStart":4,"sourceCodeEnd":28,"githubUrl":"https://github.com/perwendel/spark/blob/1973e402f5d4c1442ad34a1d38ed0758079f7773/src/main/java/spark/embeddedserver/jetty/websocket/WebSocketHandlerWrapper.java#L4-L28","documentation":"Spark's Jetty WebSocket integration requires every registered WebSocket handler class to either implement Jetty's WebSocketListener interface or be annotated with Spark's @WebSocket annotation. validateHandlerClass performs this check before wrapping the class in a WebSocketHandlerWrapper. If neither condition holds, the class cannot be attached to a Jetty WebSocket servlet, so Spark fails fast with IllegalArgumentException.","triggerScenarios":"Calling WebSocketHandlerWrapper.validateHandlerClass(handlerClass) (via webSocket(...) registration paths) with a class that neither implements org.eclipse.jetty.websocket.api.WebSocketListener nor carries the spark.websocket.@WebSocket annotation.","commonSituations":"Developers create a plain POJO WebSocket handler and pass it to Spark's webSocket(\"/path\", Handler.class) without implementing WebSocketListener or adding @WebSocket; migrations from other WebSocket libraries where the old handler class lacks the required interface/annotation; typos where the annotation imported is the wrong @WebSocket.","solutions":["Make the handler class implement org.eclipse.jetty.websocket.api.WebSocketListener (onWebSocketConnect/Close/Error/Message methods).","Alternatively annotate the handler class with spark's @WebSocket annotation (with an onWebSocket... annotated method).","Verify the correct annotation is imported (spark.websocket.WebSocket, not a Jetty or other library's WebSocket annotation)."],"exampleFix":"// before\nclass ChatHandler { /* no interface, no annotation */ }\nwebSocket(\"/chat\", ChatHandler.class); // throws\n\n// after\nimport spark.websocket.WebSocket;\nimport org.eclipse.jetty.websocket.api.*;\n@WebSocket\nclass ChatHandler implements WebSocketListener {\n    public void onWebSocketConnect(Session s) { }\n    public void onWebSocketClose(int c, String m) { }\n    public void onWebSocketError(Throwable t) { }\n    public void onWebSocketText(String m) { }\n    public void onWebSocketBinary(byte[] p, int o, int l) { }\n}","handlingStrategy":"validation","validationCode":"boolean valid = WebSocketListener.class.isAssignableFrom(HandlerClass.class)\n        || HandlerClass.class.isAnnotationPresent(spark.websocket.WebSocket.class);\nif (!valid) throw new IllegalArgumentException(HandlerClass + \" is not a valid WebSocket handler\");","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always implement WebSocketListener or annotate handlers with spark's @WebSocket.","Add a unit test that reflectively validates every handler passed to webSocket(...).","Double-check annotation imports when an IDE offers multiple @WebSocket types."],"tags":["websocket","jetty","illegal-argument","spark"],"backgroundTag":"invalid-argument-value","analyzedSha":"1973e402f5d4c1442ad34a1d38ed0758079f7773","analyzedAt":"2026-09-10T14:38:22.866Z","contentChangedAt":"2026-09-10T14:38:22.866Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}