thedotmack/claude-mem · error

Connection failed, killing subprocess tree to prevent zombie

Error message

Connection failed, killing subprocess tree to prevent zombie

What it means

The MCP client could not establish a connection to the chroma-mcp subprocess (spawn failure, early exit, or handshake timeout). ChromaMcpManager tree-kills the subprocess so uv/python descendants cannot survive on Linux (#2313), then rethrows the original connection error. Vector search is unavailable until the next connect attempt.

Source

Thrown at src/services/sync/ChromaMcpManager.ts:284

    });

    try {
      await Promise.race([mcpConnectionPromise, timeoutPromise]);
      this.assertConnectionNotCancelled(connectionGeneration);
    } catch (connectionError) {
      clearTimeout(timeoutId!);
      if (
        connectionError instanceof ChromaMcpConnectionCancelledError ||
        this.connectionGeneration !== connectionGeneration
      ) {
        logger.debug('CHROMA_MCP', 'MCP connection cancelled during shutdown');
        await this.disposeCurrentSubprocess();
        throw connectionError instanceof ChromaMcpConnectionCancelledError
          ? connectionError
          : new ChromaMcpConnectionCancelledError();
      }
      const stderrTail = transportStderrTail();
      logger.warn('CHROMA_MCP', 'Connection failed, killing subprocess tree to prevent zombie', {
        error: connectionError instanceof Error ? connectionError.message : String(connectionError),
        ...(stderrTail ? { stderrTail } : {})
      });
      // Tree-kill (not just transport.close) so failed-connect descendants
      // can't survive on Linux (#2313).
      await this.disposeCurrentSubprocess();
      throw connectionError;
    }
    clearTimeout(timeoutId!);

    this.connected = true;
    this.registerManagedProcess();
    clearDependencyStatus('chroma');

    logger.info('CHROMA_MCP', 'Connected to chroma-mcp successfully');

    const currentTransport = this.transport;
    // Captured HERE, while the child is alive and attached — not in the

View on GitHub (pinned to 8bc631a71a)

Solutions

  1. Read the logged error and stderrTail fields — they distinguish spawn failure from crash from timeout
  2. Run the logged command manually (e.g. uvx chroma-mcp) once to warm the cache and surface the real error
  3. Install uv and make sure it is on the PATH of the user running the worker
  4. Raise the connection timeout if first-run downloads are slow on your network
  5. Clear a corrupt cache with: uv cache clean
Defensive patterns

Strategy: retry

Validate before calling

import { execFile } from 'node:child_process';
import { promisify } from 'node:util';
const execFileP = promisify(execFile);

async function uvxAvailable(): Promise<boolean> {
  try {
    await execFileP('uvx', ['--version']);
    return true;
  } catch {
    return false;
  }
}

// preflight before first Chroma use
if (!(await uvxAvailable())) {
  // degrade to non-vector features instead of attempting connect()
}

Try / catch

try {
  await manager.connect();
} catch (err) {
  // run degraded (FTS/LIKE search only); schedule reconnect with backoff;
  // the manager already tree-killed the failed subprocess
  enterDegradedMode();
  scheduleReconnect(30_000);
}

Prevention

When it happens

Trigger: connect() spawning uvx chroma-mcp when uv/uvx is missing from PATH (ENOENT); first-run package download exceeding the connect timeout; an unsupported Python version; the process exiting before the MCP handshake; stderr captured in stderrTail showing import or dependency errors.

Common situations: uv not installed or absent from the service PATH (launchd, systemd, CI runners strip PATH); offline or proxied networks blocking PyPI; a stale uv cache holding a corrupted chroma-mcp download.

Related errors


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