thedotmack/claude-mem · error · Error

chroma-mcp transport error during

Error message

chroma-mcp transport error during "${toolName}" (retry failed): ${retryError instanceof Error ? retryError.message : String(retryError)}

What it means

Generic Error thrown when the single reconnect-and-retry for a failed chroma-mcp tool call also fails. The first attempt hit a transport error, the manager disposed the subprocess and reconnected, but the retry (ensureConnected or the second callTool) threw; the manager marks itself disconnected and wraps the retry failure in a descriptive transport error naming the tool and original failure.

Solutions

  1. Inspect the wrapped retryError message to find the root cause of the retry failure.
  2. Verify uv/uvx is installed and can launch chroma-mcp (run the uvx command manually with the same args).
  3. Pin/upgrade the chroma-mcp package version; an incompatible update often causes immediate subprocess crashes.
  4. Check system resources (memory, file descriptors) that could kill the respawned subprocess.
  5. Catch this error, wait, and retry with backoff — the manager sets connected=false so the next call triggers a fresh reconnect.
  6. If shutdown was in progress, the underlying cause may be a cancellation surfaced here; treat accordingly.

Example fix

// before
const result = await manager.callTool('chroma_query_documents', args); // throws on transient subprocess crash
// after
let result;
for (let attempt = 0; attempt < 3; attempt++) {
  try {
    result = await manager.callTool('chroma_query_documents', args);
    break;
  } catch (e) {
    if (String(e.message).includes('transport error') && attempt < 2) {
      await new Promise(r => setTimeout(r, 500 * 2 ** attempt));
      continue;
    }
    throw e;
  }
}
Defensive patterns

Strategy: retry

Validate before calling

// Pre-flight: confirm uvx can launch chroma-mcp before issuing calls
const { execFileSync } = require('child_process');
try { execFileSync('uvx', ['--version'], { stdio: 'ignore' }); }
catch { throw new Error('uv/uvx unavailable; chroma-mcp cannot be respawned'); }

Type guard

function isTransportRetryFailure(e: unknown): boolean {
  return e instanceof Error && e.message.includes('transport error') && e.message.includes('retry failed');
}

Try / catch

try {
  result = await manager.callTool(toolName, args);
} catch (e) {
  if (/transport error .*\(retry failed\)/.test((e as Error)?.message ?? '')) {
    await sleep(backoffMs);
    result = await manager.callTool(toolName, args); // next call triggers fresh reconnect
  } else { throw e; }
}

Prevention

When it happens

Trigger: client.callTool() throws a transport error (subprocess died, stdio stream broken), and after disposeCurrentSubprocess + ensureConnected the retried callTool or reconnection throws again — e.g. uvx cannot respawn chroma-mcp, port/resource unavailable, or the child crashes immediately.

Common situations: Missing or broken uv/uvx installation so chroma-mcp cannot be relaunched; chroma-mcp version incompatibility causing instant crash; system resource exhaustion (OOM, fd limits); network/stdio corruption under load.

Understand the failure class

Background: ECONNREFUSED and "connection refused" / "could not connect to server" errors: what they mean and how to fix them — this error's family across 44 libraries.

Related errors


AI-assisted analysis of thedotmack/claude-mem@d8bc9755e7 (2026-09-17). Data as JSON: /api/errors/94f8e5b541e6bbfa. Report an issue: GitHub.

Appendix: source

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

      }

      // Tree-kill the dying subprocess before reconnect. Previously this path
      // just nulled the handle, which on Linux leaks the uv/python/chroma-mcp
      // descendants every time a transport error happens (#2313).
      await this.disposeCurrentSubprocess();

      try {
        if (callGeneration !== this.connectionGeneration) {
          throw new ChromaMcpConnectionCancelledError('chroma-mcp call cancelled during shutdown');
        }
        await this.ensureConnected();
        result = await this.client!.callTool({
          name: toolName,
          arguments: toolArguments
        });
      } catch (retryError) {
        this.connected = false;
        throw new Error(`chroma-mcp transport error during "${toolName}" (retry failed): ${retryError instanceof Error ? retryError.message : String(retryError)}`);
      }
    }

    if (result.isError) {
      const errorText = (result.content as Array<{ type: string; text?: string }>)
        ?.find(item => item.type === 'text')?.text || 'Unknown chroma-mcp error';
      throw new Error(`chroma-mcp tool "${toolName}" returned error: ${errorText}`);
    }

    const contentArray = result.content as Array<{ type: string; text?: string }>;
    if (!contentArray || contentArray.length === 0) {
      return null;
    }

    const firstTextContent = contentArray.find(item => item.type === 'text' && item.text);
    if (!firstTextContent || !firstTextContent.text) {
      return null;
    }

View on GitHub (pinned to d8bc9755e7)