thedotmack/claude-mem · warning
chroma-mcp subprocess closed unexpectedly, applying reconnec
Error message
chroma-mcp subprocess closed unexpectedly, applying reconnect backoff
What it means
The Chroma MCP client runs `chroma-mcp` (via uvx) as a stdio subprocess. When its transport closes while the connection is current, not intentionally being closed, and belongs to this connection generation, the manager marks itself disconnected, unregisters from the supervisor, and schedules a reconnect with backoff plus a best-effort descendant sweep (on Linux the uv/python grandchildren outlive uvx — issue #2313).
Source
Thrown at src/services/sync/ChromaMcpManager.ts:319
const currentTransport = this.transport;
// Captured HERE, while the child is alive and attached — not in the
// onclose handler below, which by definition runs after it has died.
const transportChild = (this.transport as unknown as { _process?: ChildProcess })._process;
const currentTracked = transportChild ? trackChild(transportChild) : null;
const currentTrackedPid = currentTracked?.pid;
this.transport.onclose = () => {
if (this.transport !== currentTransport) {
logger.debug('CHROMA_MCP', 'Ignoring stale onclose from previous transport');
return;
}
if (
this.connectionGeneration !== connectionGeneration ||
this.intentionallyClosingTransports.has(currentTransport as unknown as object)
) {
logger.debug('CHROMA_MCP', 'Ignoring onclose from intentionally closed transport');
return;
}
logger.warn('CHROMA_MCP', 'chroma-mcp subprocess closed unexpectedly, applying reconnect backoff');
this.connected = false;
getSupervisor().unregisterProcess(CHROMA_SUPERVISOR_ID);
this.client = null;
this.transport = null;
this.lastConnectionFailureTimestamp = Date.now();
// Direct child (uvx) emitted close, but on Linux the grandchildren
// (uv/python/chroma-mcp) often outlive their parent because MCP SDK
// does not use process groups. Sweep the descendant tree using the
// captured PID — best-effort; pgrep returns nothing if everything
// already exited (#2313).
this.scheduleUnexpectedCloseCleanup(currentTracked);
};
}
private scheduleUnexpectedCloseCleanup(tracked: TrackedChild | null): void {
let cleanup: Promise<void>;
cleanup = this.cleanupUnexpectedCloseSubprocess(tracked).finally(() => {View on GitHub (pinned to 8bc631a71a)
Solutions
- Verify uvx works: `uvx --version` (re-run the installer to re-provision uv/python if not).
- Check the captured subprocess output tail in logs for the crash reason.
- Let the backoff reconnect run; if it never reconnects, restart the worker.
- Free memory if an OOM kill is suspected.
Defensive patterns
Strategy: retry
Validate before calling
import { spawnSync } from 'node:child_process';
const uvxOk = spawnSync('uvx', ['--version'], { encoding: 'utf8' }).status === 0; Prevention
- Keep uv/uvx installed and on PATH.
- Ensure enough memory for the Python chroma-mcp subprocess.
- Update claude-mem regularly so the pinned chroma-mcp stays compatible.
When it happens
Trigger: The chroma-mcp subprocess dies — Python crash, missing uv/uvx, OOM kill, or stdio EOF — while the manager considered the connection live.
Common situations: Broken uv installation, incompatible chroma-mcp version, memory pressure killing Python, or system sleep/resume closing the pipes.
Related errors
- Connection failed, killing subprocess tree to prevent zombie
- chroma-mcp transport error during "${toolName}" (retry faile
- chroma-mcp tool "${toolName}" returned error: ${errorText}
- chroma-mcp uvx prewarm failed
- Transport error during "${toolName}", reconnecting and retry
AI-assisted analysis of thedotmack/claude-mem@8bc631a71a (2026-08-20).
Data as JSON: /api/errors/34e538e42cf8eb0a.
Report an issue: GitHub.