{"record":{"id":"c9f163d29af7b9cc","repo":"TooTallNate/Java-WebSocket","slug":"cannot-call-setdaemon-after-server-is-already-star","errorCode":null,"errorMessage":"Cannot call setDaemon after server is already started!","messagePattern":"Cannot call setDaemon after server is already started!","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"src/main/java/org/java_websocket/server/WebSocketServer.java","lineNumber":362,"sourceCode":"   *\n   * @return The port number.\n   */\n  public int getPort() {\n    int port = getAddress().getPort();\n    if (port == 0 && server != null) {\n      port = server.socket().getLocalPort();\n    }\n    return port;\n  }\n\n  @Override\n  public void setDaemon(boolean daemon) {\n    // pass it to the AbstractWebSocket too, to use it on the connectionLostChecker thread factory\n    super.setDaemon(daemon);\n    // we need to apply this to the decoders as well since they were created during the constructor\n    for (WebSocketWorker w : decoders) {\n      if (w.isAlive()) {\n        throw new IllegalStateException(\"Cannot call setDaemon after server is already started!\");\n      } else {\n        w.setDaemon(daemon);\n      }\n    }\n  }\n\n  /**\n   * Get the list of active drafts\n   *\n   * @return the available drafts for this server\n   */\n  public List<Draft> getDraft() {\n    return Collections.unmodifiableList(drafts);\n  }\n\n  /**\n   * Set the requested maximum number of pending connections on the socket. The exact semantics are\n   * implementation specific. The value provided should be greater than 0. If it is less than or","sourceCodeStart":344,"sourceCodeEnd":380,"githubUrl":"https://github.com/TooTallNate/Java-WebSocket/blob/afeacbf8c0f6f6a761c9d9daed8c813dd3b8ed7d/src/main/java/org/java_websocket/server/WebSocketServer.java#L344-L380","documentation":"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.","triggerScenarios":"Calling server.setDaemon(true/false) after start() (or run()) has spawned the decoder threads; flipping daemon mode dynamically at runtime.","commonSituations":"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.","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."],"exampleFix":"// before\nserver.start();\nserver.setDaemon(true); // throws: decoders alive\n// after\nserver.setDaemon(true);\nserver.start();","handlingStrategy":"validation","validationCode":"if (server.selectorthread != null) {\n  throw new IllegalStateException(\"setDaemon must be called before start()\");\n}\nserver.setDaemon(daemon);","typeGuard":null,"tryCatchPattern":"try {\n  server.setDaemon(daemon);\n} catch (IllegalStateException e) {\n  log.warn(\"Cannot change daemon mode after start; applying on next restart\");\n}","preventionTips":["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"],"tags":["websocket","threading","lifecycle"],"backgroundTag":"invalid-state-transition","analyzedSha":"afeacbf8c0f6f6a761c9d9daed8c813dd3b8ed7d","analyzedAt":"2026-09-09T14:39:47.546Z","contentChangedAt":"2026-09-09T14:39:47.546Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}