thedotmack/claude-mem · warning
Failed to reap orphaned chroma-mcp descendant
Error message
Failed to reap orphaned chroma-mcp descendant
What it means
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.
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.
Example fix
// before
if (code !== 'ESRCH') { logger.warn(...); }
// after: handle EPERM explicitly with guidance
if (code === 'EPERM') {
logger.warn('CHROMA_MCP', `Cannot kill orphan ${pid}: permission denied; kill manually`);
} else if (code !== 'ESRCH') {
logger.warn('CHROMA_MCP', 'Failed to reap orphaned chroma-mcp descendant', { pid, code });
} Defensive patterns
Strategy: try-catch
Validate before calling
// check you can signal the pid first
try {
process.kill(pid, 0); // existence/permission probe
} catch (e) {
console.log(`pid ${pid} not signallable: ${e.code}`);
} Try / catch
try { process.kill(pid, 'SIGKILL'); }
catch (e) {
const code = (e as NodeJS.ErrnoException).code;
if (code !== 'ESRCH') console.warn(`reap failed pid=${pid} code=${code}`);
} Prevention
- 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
When it happens
Trigger: SIGKILL on a descendant pid raises EPERM (owned by another user), EINVAL, or another errno. Only ESRCH (no such process) is silently tolerated.
Common situations: Reaper running as a different user than the process that spawned chroma-mcp, containerized setups restricting signals between processes, or pid reuse races.
Understand the failure class
Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.
Related errors
- chroma-mcp connection failed
- chroma-mcp subprocess closed unexpectedly, applying…
- chroma-mcp transport error during
- chroma-mcp uvx prewarm failed
- claude-mem does not appear to be installed.
AI-assisted analysis of thedotmack/claude-mem@d8bc9755e7 (2026-09-17).
Data as JSON: /api/errors/4840fa7f49f8db73.
Report an issue: GitHub.
Appendix: source
Thrown at src/services/sync/ChromaMcpManager.ts:1178
const seen = new Set<number>();
for (const { pid, startToken } of entries) {
if (seen.has(pid)) continue;
seen.add(pid);
if (!isPidAlive(pid)) continue;
if (!isSameProcess(pid, startToken)) {
logger.debug('CHROMA_MCP', 'Skipping reap: PID was recycled since the snapshot', { pid });
continue;
}
try {
process.kill(pid, 'SIGKILL');
logger.debug('CHROMA_MCP', 'Reaped orphaned chroma-mcp descendant', { pid });
} catch (error) {
const code = (error as NodeJS.ErrnoException).code;
if (code !== 'ESRCH') {
logger.warn('CHROMA_MCP', 'Failed to reap orphaned chroma-mcp descendant', {
pid,
code,
});
}
}
}
}
private async disposeActivePrewarm(): Promise<void> {
const prewarmChild = this.activePrewarmChild;
const tracked = this.activePrewarmTracked;
if (!prewarmChild) {
return;
}
if (this.activePrewarmChild === prewarmChild) {
this.activePrewarmChild = null;
this.activePrewarmTracked = null;
}View on GitHub (pinned to d8bc9755e7)