thedotmack/claude-mem · warning

failed to kill prior chroma-mcp tree (best-effort)

Error message

failed to kill prior chroma-mcp tree (best-effort)

What it means

During disposal of the current chroma-mcp connection, killProcessTree(pid) threw and was logged as best-effort. Shutdown continues (transport.close, client.close, direct SIGKILL paths), but a failed tree-kill risks orphaned uv/python descendants — the Linux zombie problem (#2313) this disposal path exists to prevent.

Source

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

   * Idempotent and best-effort — safe to call when there is no active
   * subprocess (no-op in that case).
   */
  private async disposeCurrentSubprocess(): Promise<void> {
    await this.disposeActivePrewarm();

    const closingTransport = this.transport;
    if (closingTransport) {
      this.intentionallyClosingTransports.add(closingTransport as unknown as object);
    }

    const chromaProcess = (this.transport as unknown as { _process?: ChildProcess })?._process;
    const trackedPid = chromaProcess?.pid;

    if (trackedPid) {
      try {
        await ChromaMcpManager.killProcessTree(trackedPid);
      } catch (error) {
        logger.warn('CHROMA_MCP', 'failed to kill prior chroma-mcp tree (best-effort)', {
          pid: trackedPid,
          error: error instanceof Error ? error.message : String(error)
        });
      }
    }

    if (closingTransport) {
      try { await closingTransport.close(); } catch { /* already dead */ }
    }
    if (this.client) {
      try { await this.client.close(); } catch { /* already dead */ }
    }

    if (trackedPid) {
      getSupervisor().unregisterProcess(CHROMA_SUPERVISOR_ID);
    }
    this.releaseChromaWriterLock();

View on GitHub (pinned to e2d1df569a)

Solutions

  1. Check for orphans afterwards: pgrep -af 'chroma-mcp|uvx' and kill any leftovers manually
  2. Treat as best-effort — the manager completes shutdown regardless
  3. If orphans accumulate repeatedly, upgrade claude-mem (#2313-era fixes) and stop the worker with SIGTERM so disposal paths can run
Defensive patterns

Strategy: fallback

Validate before calling

import { execSync } from 'node:child_process';

function findChromaOrphans(): string[] {
  if (process.platform !== 'linux') return [];
  try {
    return execSync("pgrep -af 'chroma-mcp|uvx'").toString().trim().split(String.fromCharCode(10));
  } catch {
    return []; // pgrep exits 1 when nothing matches
  }
}

Prevention

When it happens

Trigger: The pid was already reaped by another cleaner (ESRCH race), permission denied on a process owned by a different user after a privilege change, or the process exiting between pid capture and the kill call.

Common situations: Rapid reconnect cycles; process supervisors (systemd) reaping children first; containers with restricted process permissions.

Related errors


AI-assisted analysis of thedotmack/claude-mem@e2d1df569a (2026-08-20). Data as JSON: /api/errors/214470681cd1c5d4. Report an issue: GitHub.