{"record":{"id":"1fa1de9e04802e81","repo":"can1357/oh-my-pi","slug":"lsp-mux-already-listening-on-endpoint","errorCode":null,"errorMessage":"LSP mux already listening on ${endpoint}","messagePattern":"LSP mux already listening on (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/lsp/mux/server.ts","lineNumber":252,"sourceCode":"\t\t\tawait promise;\n\t\t}\n\t\tif (process.platform !== \"win32\" && this.#endpoint) {\n\t\t\ttry {\n\t\t\t\tawait fs.unlink(this.#endpoint);\n\t\t\t} catch {\n\t\t\t\t// The socket may already have been removed by process cleanup.\n\t\t\t}\n\t\t}\n\t}\n\n\tasync #clearStaleSocket(endpoint: string): Promise<void> {\n\t\ttry {\n\t\t\tawait fs.stat(endpoint);\n\t\t} catch {\n\t\t\treturn;\n\t\t}\n\t\tconst alive = await this.#probe(endpoint);\n\t\tif (alive) throw new Error(`LSP mux already listening on ${endpoint}`);\n\t\ttry {\n\t\t\tawait fs.unlink(endpoint);\n\t\t} catch (error) {\n\t\t\tlogger.warn(\"Failed to remove stale LSP mux socket\", { endpoint, error: String(error) });\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\tasync #probe(endpoint: string): Promise<boolean> {\n\t\tconst { promise, resolve } = Promise.withResolvers<boolean>();\n\t\tconst socket = net.createConnection(endpoint);\n\t\tsocket.once(\"connect\", () => {\n\t\t\tsocket.destroy();\n\t\t\tresolve(true);\n\t\t});\n\t\tsocket.once(\"error\", () => {\n\t\t\tsocket.destroy();\n\t\t\tresolve(false);","sourceCodeStart":234,"sourceCodeEnd":270,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/lsp/mux/server.ts#L234-L270","documentation":"The LSP mux Unix-domain socket server throws this when starting a listener finds an existing socket file at the endpoint that still answers a liveness probe. It prevents a second mux from silently hijacking a socket owned by a live daemon, which would break all connected clients.","triggerScenarios":"Calling listen() on an LspMuxServer when #clearStaleSocket finds the socket file exists and the #probe() ping succeeds, i.e. another live mux daemon is already bound to that endpoint.","commonSituations":"Launching a second `omp lsp mux` manually while a detached daemon is already running; stale environment pointing at another project's live mux; running two omp processes with the same mux endpoint configured.","solutions":["Do nothing — a healthy mux is already running on this endpoint; connect to it instead of starting a new server.","Stop the existing daemon (`omp lsp stop` or kill the mux process) before restarting.","Delete or change the mux socket endpoint configuration if the running daemon is unwanted.","If the socket is actually stale (probe race), remove it manually and retry."],"exampleFix":"// before\nawait new LspMuxServer().listen(endpoint);\n// after\nif (await isLspMuxAlive(endpoint)) return; // reuse existing daemon\nawait new LspMuxServer().listen(endpoint);","handlingStrategy":"try-catch","validationCode":"import * as fs from \"node:fs/promises\";\nasync function muxSocketInUse(endpoint: string) {\n  try { await fs.stat(endpoint); return true; } catch { return false; }\n}\n// skip starting a mux if muxSocketInUse(endpoint)","typeGuard":null,"tryCatchPattern":"try {\n  await server.listen(endpoint);\n} catch (err) {\n  if (err instanceof Error && err.message.includes(\"already listening\")) {\n    // reuse the running daemon; continue\n  } else throw err;\n}","preventionTips":["Check for a live mux (status/IPC ping) before starting one.","Use one shared daemon per project instead of spawning per-process muxes.","Clean up stale sockets on shutdown but always probe before unlinking."],"tags":["lsp","ipc","unix-socket","lifecycle"],"backgroundTag":"socket-already-in-use","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}