TooTallNate/Java-WebSocket · error · IllegalStateException
Cannot call setDaemon after server is already started!
Error message
Cannot call setDaemon after server is already started!
What it means
setDaemon() propagates the daemon flag to the decoder WebSocketWorker threads, which are created in the constructor. If any decoder thread is already alive the server is running and thread daemon status can no longer be changed, so an IllegalStateException is thrown.
Solutions
- Call setDaemon() before start(), right after construction.
- Check whether the server has started (e.g. track a started flag or selectorthread) and skip/reject the setDaemon call otherwise.
- To change daemon mode at runtime, stop the server, create a new instance, setDaemon, then start.
Example fix
// before server.start(); server.setDaemon(true); // throws: decoders alive // after server.setDaemon(true); server.start();
Defensive patterns
Strategy: validation
Validate before calling
if (server.selectorthread != null) {
throw new IllegalStateException("setDaemon must be called before start()");
}
server.setDaemon(daemon); Try / catch
try {
server.setDaemon(daemon);
} catch (IllegalStateException e) {
log.warn("Cannot change daemon mode after start; applying on next restart");
} Prevention
- Apply all configuration (daemon, timeouts, reuseAddr) immediately after construction, before start()
- Centralize server construction+configuration in one factory method so config always precedes start
- Never mutate server settings from callbacks like onStart
When it happens
Trigger: Calling server.setDaemon(true/false) after start() (or run()) has spawned the decoder threads; flipping daemon mode dynamically at runtime.
Common situations: Config applied asynchronously after server startup; a settings UI updating daemon mode while the server is live; initialization-order bugs where configuration arrives post-start.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- can only be started once.
- buffer size < 0
- parameter must not be null
- Invalid SSL status:
- Buffer underflow occurred after a wrap. I don't think we…
AI-assisted analysis of TooTallNate/Java-WebSocket@afeacbf8c0 (2026-09-09).
Data as JSON: /api/errors/c9f163d29af7b9cc.
Report an issue: GitHub.
Appendix: source
Thrown at src/main/java/org/java_websocket/server/WebSocketServer.java:362
*
* @return The port number.
*/
public int getPort() {
int port = getAddress().getPort();
if (port == 0 && server != null) {
port = server.socket().getLocalPort();
}
return port;
}
@Override
public void setDaemon(boolean daemon) {
// pass it to the AbstractWebSocket too, to use it on the connectionLostChecker thread factory
super.setDaemon(daemon);
// we need to apply this to the decoders as well since they were created during the constructor
for (WebSocketWorker w : decoders) {
if (w.isAlive()) {
throw new IllegalStateException("Cannot call setDaemon after server is already started!");
} else {
w.setDaemon(daemon);
}
}
}
/**
* Get the list of active drafts
*
* @return the available drafts for this server
*/
public List<Draft> getDraft() {
return Collections.unmodifiableList(drafts);
}
/**
* Set the requested maximum number of pending connections on the socket. The exact semantics are
* implementation specific. The value provided should be greater than 0. If it is less than orView on GitHub (pinned to afeacbf8c0)