perwendel/spark · error · IllegalStateException
WebSockets are only supported in the embedded server
Error message
WebSockets are only supported in the embedded server
What it means
WebSocket handlers in Spark are registered via webSocket(path, wrapper), which delegates to addWebSocketHandler. WebSockets require Spark's own embedded Jetty server; when Spark is running as a servlet inside an external container (isRunningFromServlet() is true) it cannot install its WebSocket support, so registration throws IllegalStateException.
Solutions
- Run the app with the embedded Spark server (main() with Spark.port/threadPool etc.) instead of deploying as a WAR.
- Handle WebSockets with the servlet container's own native WebSocket support (javax.websocket endpoints) when servlet deployment is mandatory.
- Remove or conditionally guard webSocket() registration when running in servlet mode.
Example fix
// before
public class App extends SparkApplication { // deployed as WAR
public void init() { webSocket("/ws", WsHandler.class); } // throws
}
// after
// deploy with embedded server: run App.main() directly, or use container-native JSR-356 endpoints for /ws Defensive patterns
Strategy: validation
Validate before calling
if (!isEmbeddedMode()) { // e.g. you deploy as WAR
throw new IllegalStateException("Register WebSockets only in embedded mode");
}
Spark.webSocket("/ws", WsHandler.class); Try / catch
try {
Spark.webSocket("/ws", WsHandler.class);
} catch (IllegalStateException e) {
LOG.warn("WebSockets unavailable in servlet mode; using container-native endpoints");
} Prevention
- Know your deployment mode: WAR in Tomcat => no Spark WebSockets.
- Centralize WebSocket registration in embedded-only bootstrap code.
- Document in your deploy pipeline that WAR deployments need JSR-356 endpoints instead.
When it happens
Trigger: Calling webSocket("/ws", handler) (or webSocketAnnotation) while the app is deployed as a WAR in an external servlet container such as Tomcat/WildFly, i.e. running with the spark-servlet bootstrap instead of the embedded server.
Common situations: Deploying a Spark app as a WAR to a corporate Tomcat instance and adding WebSocket endpoints; switching from embedded jetty (dev) to servlet deployment (prod) without removing WebSocket routes.
Related errors
- Could not instantiate websocket handler
- HttpServletRequest cannot be null.
- This must be done after route mapping has begun
- Must provide a keystore file to run secured
- Server has not been properly initialized
AI-assisted analysis of perwendel/spark@1973e402f5 (2026-09-10).
Data as JSON: /api/errors/7f8f72522f4fa0e7.
Report an issue: GitHub.
Appendix: source
Thrown at src/main/java/spark/Service.java:427
/**
* Maps the given path to the given WebSocket handler instance.
* <p>
* This is currently only available in the embedded server mode.
*
* @param path the WebSocket path.
* @param handler the handler instance that will manage the WebSocket connection to the given path.
*/
public void webSocket(String path, Object handler) {
addWebSocketHandler(path, new WebSocketHandlerInstanceWrapper(handler));
}
private synchronized void addWebSocketHandler(String path, WebSocketHandlerWrapper handlerWrapper) {
if (initialized) {
throwBeforeRouteMappingException();
}
if (isRunningFromServlet()) {
throw new IllegalStateException("WebSockets are only supported in the embedded server");
}
requireNonNull(path, "WebSocket path cannot be null");
if (webSocketHandlers == null) {
webSocketHandlers = new HashMap<>();
}
webSocketHandlers.put(path, handlerWrapper);
}
/**
* Sets the max idle timeout in milliseconds for WebSocket connections.
*
* @param timeoutMillis The max idle timeout in milliseconds.
* @return the object with max idle timeout set for WebSocket connections
*/
public synchronized Service webSocketIdleTimeoutMillis(long timeoutMillis) {
if (initialized) {
throwBeforeRouteMappingException();View on GitHub (pinned to 1973e402f5)