{"record":{"id":"4407930ed4c0ef84","repo":"thedotmack/claude-mem","slug":"failed-to-remove-pid-file","errorCode":null,"errorMessage":"Failed to remove PID file","messagePattern":"Failed to remove PID file","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"src/services/infrastructure/ProcessManager.ts","lineNumber":161,"sourceCode":"    return JSON.parse(readFileSync(PID_FILE, 'utf-8'));\n  } catch (error: unknown) {\n    if (error instanceof Error) {\n      logger.warn('SYSTEM', 'Failed to parse PID file', { path: PID_FILE }, error);\n    } else {\n      logger.warn('SYSTEM', 'Failed to parse PID file', { path: PID_FILE }, new Error(String(error)));\n    }\n    return null;\n  }\n}\n\nexport function removePidFile(): void {\n  if (!existsSync(PID_FILE)) return;\n\n  try {\n    unlinkSync(PID_FILE);\n  } catch (error: unknown) {\n    if (error instanceof Error) {\n      logger.warn('SYSTEM', 'Failed to remove PID file', { path: PID_FILE }, error);\n    } else {\n      logger.warn('SYSTEM', 'Failed to remove PID file', { path: PID_FILE }, new Error(String(error)));\n    }\n  }\n}\n\n/**\n * Owner-or-dead guarded PID-file removal (Phase 5, worker-restart plan).\n *\n * Deletes the PID file only when the recorded pid is `expectedOwnerPid` (the\n * worker the caller just shut down, or the caller itself) OR is no longer\n * alive — the shared guard in supervisor/shutdown.ts with `deleteIfDead` on,\n * so this helper may clean dead leftovers while the shutdown cascade only\n * ever deletes its own file.\n */\nexport function removePidFileIfOwner(expectedOwnerPid: number | null): void {\n  removeOwnedPidFile(PID_FILE, expectedOwnerPid, true);\n}","sourceCodeStart":143,"sourceCodeEnd":179,"githubUrl":"https://github.com/thedotmack/claude-mem/blob/e2d1df569a8f04075d40e92461128ece7cf04c82/src/services/infrastructure/ProcessManager.ts#L143-L179","documentation":"removePidFile unlinks the worker PID file during shutdown. This warning (Error branch) fires when unlinkSync throws after existsSync passed — EACCES/EPERM when permissions or ownership changed, EBUSY on Windows while another handle holds the file, or ENOENT when the file vanished between the exists check and the unlink (a TOCTOU race). The error is swallowed and shutdown continues.","triggerScenarios":"unlinkSync(PID_FILE) throws: ownership changed (a sudo run made root own the file), the file sits on a read-only mount, antivirus or an open handle locks it on Windows, or a concurrent cleanup deleted it in the race window.","commonSituations":"Two shutdown paths racing (supervisor and worker both cleaning up); running once under sudo so root owns the file; Windows Defender scanning the file at unlink time; data dir on a read-only filesystem.","solutions":["Read the logged errno: ENOENT is benign (already removed); EACCES/EPERM needs a permission or ownership fix.","Remove the file manually with the account that owns it (sudo rm if root-owned), so future runs can manage it.","Route shutdowns through one supervisor so only one actor ever deletes the PID file.","On Windows, exclude the claude-mem data dir from antivirus scanning if EBUSY/EPERM recurs."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// avoid the exists/unlink race: just attempt the unlink and classify the errno\nimport { unlinkSync } from 'node:fs';\ntry {\n  unlinkSync(PID_FILE);\n} catch (e) {\n  if ((e as NodeJS.ErrnoException).code !== 'ENOENT') throw e;\n}","typeGuard":"function isBenignUnlink(e: unknown): e is NodeJS.ErrnoException {\n  return (e as NodeJS.ErrnoException)?.code === 'ENOENT';\n}","tryCatchPattern":"try {\n  removePidFile();\n} catch (e) {\n  const code = (e as NodeJS.ErrnoException).code;\n  if (code === 'ENOENT') return;        // already gone\n  if (code === 'EACCES' || code === 'EPERM') log.warn('fix ownership of PID file');\n  else throw e;\n}","preventionTips":["Run the worker under one account so it always owns its PID file.","Never run the worker under sudo against a user-owned data dir.","Exclude the data dir from antivirus scanning on Windows."],"tags":["pid-file","unlink","filesystem","race-condition"],"backgroundTag":"unlink-permission-denied","analyzedSha":"e2d1df569a8f04075d40e92461128ece7cf04c82","analyzedAt":"2026-08-20T23:58:13.836Z","contentChangedAt":"2026-08-20T23:58:13.836Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}