{"record":{"id":"4840fa7f49f8db73","repo":"thedotmack/claude-mem","slug":"failed-to-reap-orphaned-chroma-mcp-descendant","errorCode":null,"errorMessage":"Failed to reap orphaned chroma-mcp descendant","messagePattern":"Failed to reap orphaned chroma-mcp descendant","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"src/services/sync/ChromaMcpManager.ts","lineNumber":1178,"sourceCode":"    const seen = new Set<number>();\n\n    for (const { pid, startToken } of entries) {\n      if (seen.has(pid)) continue;\n      seen.add(pid);\n      if (!isPidAlive(pid)) continue;\n\n      if (!isSameProcess(pid, startToken)) {\n        logger.debug('CHROMA_MCP', 'Skipping reap: PID was recycled since the snapshot', { pid });\n        continue;\n      }\n\n      try {\n        process.kill(pid, 'SIGKILL');\n        logger.debug('CHROMA_MCP', 'Reaped orphaned chroma-mcp descendant', { pid });\n      } catch (error) {\n        const code = (error as NodeJS.ErrnoException).code;\n        if (code !== 'ESRCH') {\n          logger.warn('CHROMA_MCP', 'Failed to reap orphaned chroma-mcp descendant', {\n            pid,\n            code,\n          });\n        }\n      }\n    }\n  }\n\n  private async disposeActivePrewarm(): Promise<void> {\n    const prewarmChild = this.activePrewarmChild;\n    const tracked = this.activePrewarmTracked;\n    if (!prewarmChild) {\n      return;\n    }\n    if (this.activePrewarmChild === prewarmChild) {\n      this.activePrewarmChild = null;\n      this.activePrewarmTracked = null;\n    }","sourceCodeStart":1160,"sourceCodeEnd":1196,"githubUrl":"https://github.com/thedotmack/claude-mem/blob/d8bc9755e74915e5c3b999181e10a67c889bce2a/src/services/sync/ChromaMcpManager.ts#L1160-L1196","documentation":"During cleanup the manager walks orphaned chroma-mcp descendant processes and SIGKILLs them. If process.kill fails with an errno other than ESRCH (process already gone), this warning is logged; the orphan may still be running.","triggerScenarios":"SIGKILL on a descendant pid raises EPERM (owned by another user), EINVAL, or another errno. Only ESRCH (no such process) is silently tolerated.","commonSituations":"Reaper running as a different user than the process that spawned chroma-mcp, containerized setups restricting signals between processes, or pid reuse races.","solutions":["Check the logged errno: EPERM means run the cleanup under the same user/with sufficient privileges.","Verify the pid still belongs to a chroma-mcp descendant and kill it manually (kill -9 <pid>).","In containers, ensure the reaper shares the PID namespace and has CAP_KILL if needed.","If benign and recurring, confirm the process exits on its own and the warning is ignorable."],"exampleFix":"// before\nif (code !== 'ESRCH') { logger.warn(...); }\n// after: handle EPERM explicitly with guidance\nif (code === 'EPERM') {\n  logger.warn('CHROMA_MCP', `Cannot kill orphan ${pid}: permission denied; kill manually`);\n} else if (code !== 'ESRCH') {\n  logger.warn('CHROMA_MCP', 'Failed to reap orphaned chroma-mcp descendant', { pid, code });\n}","handlingStrategy":"try-catch","validationCode":"// check you can signal the pid first\ntry {\n  process.kill(pid, 0); // existence/permission probe\n} catch (e) {\n  console.log(`pid ${pid} not signallable: ${e.code}`);\n}","typeGuard":null,"tryCatchPattern":"try { process.kill(pid, 'SIGKILL'); }\ncatch (e) {\n  const code = (e as NodeJS.ErrnoException).code;\n  if (code !== 'ESRCH') console.warn(`reap failed pid=${pid} code=${code}`);\n}","preventionTips":["Run the app and its cleanup under the same user","Avoid reaping pids your process did not spawn","In containers, keep children in the same PID namespace"],"tags":["subprocess","process-kill","orphan","cleanup"],"backgroundTag":"permission-denied","analyzedSha":"d8bc9755e74915e5c3b999181e10a67c889bce2a","analyzedAt":"2026-09-17T16:40:26.182Z","contentChangedAt":"2026-09-17T16:40:26.182Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}