{"record":{"id":"a80464edd97c5691","repo":"facebook/relay","slug":"another-daemon-is-already-running","errorCode":null,"errorMessage":"Another daemon is already running","messagePattern":"Another daemon is already running","errorType":"error_code","errorClass":"std::io::Error","httpStatus":null,"severity":"error","filePath":"compiler/crates/relay-compiler/src/server_daemon/socket.rs","lineNumber":76,"sourceCode":"    /// request supplies both `flush_manifest_path` and `flush_shard_dir`.\n    /// When `None`, every `Write` flushes straight to disk.\n    pub flush_writer_factory: Option<FlushWriterFactory>,\n}\n\n/// Start the Unix domain socket server.\n///\n/// This function binds to the specified socket path and accepts client connections\n/// in a loop. Each client connection is handled in a separate task.\n///\n/// The server will gracefully shut down when the shutdown signal is received.\npub async fn start_server<TPerfLogger: PerfLogger + 'static>(\n    config: ServerConfig<TPerfLogger>,\n) -> Result<(), std::io::Error> {\n    let socket_path = config.socket_path;\n    if socket_path.exists() {\n        if socket_has_listener(&socket_path) {\n            error!(\"Another daemon is already running on {:?}\", socket_path);\n            return Err(std::io::Error::new(\n                std::io::ErrorKind::AddrInUse,\n                \"Another daemon is already running\",\n            ));\n        } else {\n            info!(\n                \"Stale socket found with no connected process. Removing {:?}\",\n                socket_path\n            );\n            std::fs::remove_file(&socket_path)?;\n        }\n    }\n\n    let listener = UnixListener::bind(&socket_path)?;\n    info!(\"Server daemon listening on {:?}\", socket_path);\n\n    // Write metadata so clients can discover this daemon\n    let metadata = DaemonMetadata {\n        socket_path: socket_path.clone(),","sourceCodeStart":58,"sourceCodeEnd":94,"githubUrl":"https://github.com/facebook/relay/blob/668b1b85e06261aa3b58dabfc51f8b5524a70955/compiler/crates/relay-compiler/src/server_daemon/socket.rs#L58-L94","documentation":"The relay daemon's start_server binds a Unix socket at the configured socket_path. Before binding it checks whether a live process is already listening on that path; if socket_has_listener returns true, another daemon instance holds the socket, so it aborts with an AddrInUse io::Error to prevent two daemons competing for compiler work.","triggerScenarios":"Running `relay start` (or any command that spawns the daemon) while a previous relay daemon is still alive and listening on the same hashed socket path derived from the config path.","commonSituations":"Starting a second relay daemon in another terminal; a CI job colliding with a locally running daemon; stale daemons left over from an editor/LSP integration that never exited.","solutions":["Stop the existing daemon first (e.g. `relay server stop` or kill the relay process) and retry","Check `lsof <socket_path>` to find the PID holding the socket and kill it","Use a different --config path (the socket path is hashed from the config path) to run an independent daemon","If the daemon is actually dead but the error persists, the socket should have been cleaned as stale; remove the socket file manually and restart"],"exampleFix":"// before\nrelay start &\nrelay start            // panics/fails: AddrInUse\n// after\nrelay server stop\nrelay start","handlingStrategy":"validation","validationCode":"const socketPath = config.socketPath;\nif (fs.existsSync(socketPath)) {\n  try {\n    const client = net.connect(socketPath);\n    await new Promise((res, rej) => client.once('connect', res).once('error', rej));\n    client.end();\n    throw new Error('Daemon already running; stop it or reuse it.');\n  } catch (e) {\n    // no listener -> stale socket, safe to start\n  }\n}","typeGuard":null,"tryCatchPattern":"try {\n  await startDaemon();\n} catch (e) {\n  if (e.code === 'EADDRINUSE') {\n    console.log('Daemon already running; reusing existing daemon.');\n  } else throw e;\n}","preventionTips":["Always stop the daemon before starting a new one","Use a distinct config path per workspace so socket paths don't collide","Check with lsof/ss whether the socket has a live listener before start","In CI, run daemonless builds to avoid socket contention"],"tags":["daemon","socket","unix-socket","address-in-use"],"backgroundTag":"address-already-in-use","analyzedSha":"668b1b85e06261aa3b58dabfc51f8b5524a70955","analyzedAt":"2026-09-02T19:57:20.783Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-10T02:17:09.455Z"}