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

  1. Verify uvx works: `uvx --version` (re-run the installer to re-provision uv/python if not).
  2. Check the captured subprocess output tail in logs for the crash reason.
  3. Let the backoff reconnect run; if it never reconnects, restart the worker.
  4. 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

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


AI-assisted analysis of thedotmack/claude-mem@8bc631a71a (2026-08-20). Data as JSON: /api/errors/34e538e42cf8eb0a. Report an issue: GitHub.