perwendel/spark · error · IllegalArgumentException

WebSocket handler must implement 'WebSocketListener' or be…

Error message

WebSocket handler must implement 'WebSocketListener' or be annotated as '@WebSocket'

What it means

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.

Solutions

  1. Make the handler class implement org.eclipse.jetty.websocket.api.WebSocketListener (onWebSocketConnect/Close/Error/Message methods).
  2. Alternatively annotate the handler class with spark's @WebSocket annotation (with an onWebSocket... annotated method).
  3. Verify the correct annotation is imported (spark.websocket.WebSocket, not a Jetty or other library's WebSocket annotation).

Example fix

// before
class ChatHandler { /* no interface, no annotation */ }
webSocket("/chat", ChatHandler.class); // throws

// after
import spark.websocket.WebSocket;
import org.eclipse.jetty.websocket.api.*;
@WebSocket
class ChatHandler implements WebSocketListener {
    public void onWebSocketConnect(Session s) { }
    public void onWebSocketClose(int c, String m) { }
    public void onWebSocketError(Throwable t) { }
    public void onWebSocketText(String m) { }
    public void onWebSocketBinary(byte[] p, int o, int l) { }
}
Defensive patterns

Strategy: validation

Validate before calling

boolean valid = WebSocketListener.class.isAssignableFrom(HandlerClass.class)
        || HandlerClass.class.isAnnotationPresent(spark.websocket.WebSocket.class);
if (!valid) throw new IllegalArgumentException(HandlerClass + " is not a valid WebSocket handler");

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of perwendel/spark@1973e402f5 (2026-09-10). Data as JSON: /api/errors/9af46c8aec7208e3. Report an issue: GitHub.

Appendix: source

Thrown at src/main/java/spark/embeddedserver/jetty/websocket/WebSocketHandlerWrapper.java:22

import org.eclipse.jetty.websocket.api.annotations.WebSocket;

/**
 * A wrapper for web socket handler classes/instances.
 */
public interface WebSocketHandlerWrapper {
    
    /**
     * Gets the actual handler - if necessary, instantiating an object.
     * 
     * @return The handler instance.
     */
    Object getHandler();
    
    static void validateHandlerClass(Class<?> handlerClass) {
        boolean valid = WebSocketListener.class.isAssignableFrom(handlerClass)
                || handlerClass.isAnnotationPresent(WebSocket.class);
        if (!valid) {
            throw new IllegalArgumentException(
                    "WebSocket handler must implement 'WebSocketListener' or be annotated as '@WebSocket'");
        }
    }

}

View on GitHub (pinned to 1973e402f5)