{"record":{"id":"37fa372e038c461d","repo":"earendil-works/pi","slug":"unix-listener-path-changed-while-checking-for-a-st","errorCode":null,"errorMessage":"Unix listener path changed while checking for a stale socket: ${path}","messagePattern":"Unix listener path changed while checking for a stale socket: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/server/src/transports/unix/listener.ts","lineNumber":338,"sourceCode":"\tif (!original.isSocket()) throw new Error(`Refusing to remove non-socket Unix listener path: ${path}`);\n\tif (await isSocketLive(path)) throw new Error(`Unix listener is already running: ${path}`);\n\n\tconst preserved = join(dirname(path), `.s-${randomUUID().slice(0, 6)}`);\n\ttry {\n\t\tawait rename(path, preserved);\n\t} catch (error) {\n\t\tif (isErrorCode(error, \"ENOENT\")) return;\n\t\tthrow error;\n\t}\n\tconst current = await lstat(preserved);\n\tif (!current.isSocket() || current.dev !== original.dev || current.ino !== original.ino) {\n\t\ttry {\n\t\t\tawait lstat(path);\n\t\t} catch (error) {\n\t\t\tif (isErrorCode(error, \"ENOENT\")) await rename(preserved, path);\n\t\t\telse throw error;\n\t\t}\n\t\tthrow new Error(`Unix listener path changed while checking for a stale socket: ${path}`);\n\t}\n\tawait removePath(preserved);\n}\n\nasync function removePath(path: string): Promise<void> {\n\ttry {\n\t\tawait unlink(path);\n\t} catch (error) {\n\t\tif (!isErrorCode(error, \"ENOENT\")) throw error;\n\t}\n}\n\nfunction isSocketLive(path: string): Promise<boolean> {\n\treturn new Promise<boolean>((resolve, reject) => {\n\t\tconst socket = createConnection(path);\n\t\tlet settled = false;\n\t\tlet timer: NodeJS.Timeout | undefined;\n\t\tconst finish = (result: boolean, error?: Error): void => {","sourceCodeStart":320,"sourceCodeEnd":356,"githubUrl":"https://github.com/earendil-works/pi/blob/4af9d21d3b4d664e4a29fcabfec85171077248e3/packages/server/src/transports/unix/listener.ts#L320-L356","documentation":"Race detector in removeStaleSocket: the stale entry was renamed aside, but lstat of the preserved (.s-*) file shows it is no longer the same object (not a socket, or dev/ino differ from the original stat), and the original path was also recreated by someone else. The filesystem changed underneath the staleness check, so the removal is abandoned and the conflict reported instead of deleting an unknown file.","triggerScenarios":"Thrown at packages/server/src/transports/unix/listener.ts:338 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["The socket path changed concurrently; retry and avoid races on the path."],"exampleFix":null,"handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"4af9d21d3b4d664e4a29fcabfec85171077248e3","analyzedAt":"2026-08-24T13:07:14.692Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}