thedotmack/claude-mem · info · ChromaMcpConnectionCancelledError
chroma-mcp connection cancelled during shutdown
Error message
chroma-mcp connection cancelled during shutdown
What it means
assertConnectionNotCancelled compares the connection generation token passed into the connect flow against this.connectionGeneration. If another thread/code path bumped the generation (e.g. a shutdown or dispose started a new cycle), the in-flight connection is stale and ChromaMcpConnectionCancelledError is thrown to abandon it.
Solutions
- No fix needed — this is expected cancellation; catch ChromaMcpConnectionCancelledError and drop the pending connect.
- Avoid disposing/restarting the manager while connect() is awaiting; await or cancel connections explicitly first.
- If it fires unexpectedly, audit code paths that increment connectionGeneration (dispose, shutdown, reconnect) for races.
Example fix
// before
const p = manager.connect();
manager.dispose(); // cancels in-flight connect -> throws
await p;
// after
const p = manager.connect();
await p.catch(e => { if (!(e instanceof ChromaMcpConnectionCancelledError)) throw e; });
manager.dispose(); Defensive patterns
Strategy: try-catch
Try / catch
try {
await manager.connect();
} catch (e) {
if (e instanceof ChromaMcpConnectionCancelledError) {
return; // expected during shutdown/restart; drop the attempt
}
throw e;
} Prevention
- Do not dispose or restart the manager while a connect() is in flight.
- Await pending connections before shutdown, or treat cancellation as a no-op.
- Keep connection-generation bumps (settings reload, dispose) serialized with connect calls.
When it happens
Trigger: Calling connect() and then disposing/restarting the manager (shutdown, settings reload, generation bump) before the handshake completes; prewarmChromaMcp or connectInternal checkpoints detect the generation mismatch.
Common situations: App shutdown racing a background reconnect; hot-reloading configuration that tears down and recreates ChromaMcpManager while a connect is in flight; rapid open/close cycles in tests.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- chroma-mcp call cancelled during shutdown
- Local Chroma mutations are unavailable after shutdown begins
- queued chroma-mcp mutation cancelled during shutdown
- Backfill failed
- Chroma data dir is already owned by PID ; refusing to start…
AI-assisted analysis of thedotmack/claude-mem@d8bc9755e7 (2026-09-17).
Data as JSON: /api/errors/e0fafe98fe4107df.
Report an issue: GitHub.
Appendix: source
Thrown at src/services/sync/ChromaMcpManager.ts:398
logger.debug('CHROMA_MCP', 'Background tree-kill after onclose finished (best-effort)', {
pid,
error: error instanceof Error ? error.message : String(error)
});
} finally {
this.releaseChromaWriterLock();
}
}
private async waitForUnexpectedCloseCleanup(): Promise<void> {
const cleanup = this.unexpectedCloseCleanup;
if (cleanup) {
await cleanup;
}
}
private assertConnectionNotCancelled(connectionGeneration: number): void {
if (this.connectionGeneration !== connectionGeneration) {
throw new ChromaMcpConnectionCancelledError();
}
}
private getLocalPersistentChromaDataDir(): string | null {
const settings = SettingsDefaultsManager.loadFromFile(USER_SETTINGS_PATH);
const chromaMode = settings.CLAUDE_MEM_CHROMA_MODE || 'local';
return chromaMode === 'remote' ? null : paths.chroma();
}
private buildCommandArgs(localChromaDataDir: string | null = this.getLocalPersistentChromaDataDir()): string[] {
const settings = SettingsDefaultsManager.loadFromFile(USER_SETTINGS_PATH);
const pythonVersion = process.env.CLAUDE_MEM_PYTHON_VERSION || settings.CLAUDE_MEM_PYTHON_VERSION || '3.13';
const launcherPrefix = ChromaMcpManager.buildLauncherPrefix(pythonVersion);
if (!localChromaDataDir) {
const chromaHost = settings.CLAUDE_MEM_CHROMA_HOST || '127.0.0.1';
const chromaPort = settings.CLAUDE_MEM_CHROMA_PORT || '8000';
const chromaSsl = settings.CLAUDE_MEM_CHROMA_SSL === 'true';View on GitHub (pinned to d8bc9755e7)