{"record":{"id":"968126102212bae5","repo":"thedotmack/claude-mem","slug":"chroma-mcp-connection-failed-connectionerror-instanceof","errorCode":null,"errorMessage":"chroma-mcp connection failed: ${connectionError instanceof Error ? connectionError.message : String(connectionError)}","messagePattern":"chroma-mcp connection failed: (.+?)","errorType":"exception","errorClass":"ChromaUnavailableError","httpStatus":null,"severity":"error","filePath":"src/services/sync/ChromaMcpManager.ts","lineNumber":314,"sourceCode":"      }\n      const stderrTail = transportStderrTail();\n      logger.warn('CHROMA_MCP', 'Connection failed, killing subprocess tree to prevent zombie', {\n        error: connectionError instanceof Error ? connectionError.message : String(connectionError),\n        ...(stderrTail ? { stderrTail } : {})\n      });\n      // Tree-kill (not just transport.close) so failed-connect descendants\n      // can't survive on Linux (#2313).\n      await this.disposeCurrentSubprocess();\n      // A failed MCP handshake means Chroma is unavailable, the same as a\n      // missing uvx, a failed prewarm, or a lost writer lock. The SDK sends\n      // `notifications/initialized` right after `initialize`; when the\n      // subprocess dies mid-handshake that send throws a bare\n      // `Error: Not connected`. Classify every connect failure as\n      // ChromaUnavailableError so callers take the reconnect-backoff and\n      // skip-the-write path instead of surfacing a raw error to error tracking.\n      const unavailableMessage = `chroma-mcp connection failed: ${connectionError instanceof Error ? connectionError.message : String(connectionError)}`;\n      recordChromaVectorSearchUnavailable(unavailableMessage);\n      throw new ChromaUnavailableError(unavailableMessage, connectionError instanceof Error ? connectionError : undefined);\n    }\n    clearTimeout(timeoutId!);\n\n    this.connected = true;\n    this.registerManagedProcess();\n    clearDependencyStatus('chroma');\n\n    logger.info('CHROMA_MCP', 'Connected to chroma-mcp successfully');\n\n    const currentTransport = this.transport;\n    // Captured HERE, while the child is alive and attached — not in the\n    // onclose handler below, which by definition runs after it has died.\n    const transportChild = (this.transport as unknown as { _process?: ChildProcess })._process;\n    const currentTracked = transportChild ? trackChild(transportChild) : null;\n    const currentTrackedPid = currentTracked?.pid;\n    this.transport.onclose = () => {\n      if (this.transport !== currentTransport) {\n        logger.debug('CHROMA_MCP', 'Ignoring stale onclose from previous transport');","sourceCodeStart":296,"sourceCodeEnd":332,"githubUrl":"https://github.com/thedotmack/claude-mem/blob/d8bc9755e74915e5c3b999181e10a67c889bce2a/src/services/sync/ChromaMcpManager.ts#L296-L332","documentation":"When the chroma-mcp handshake (spawn, initialize, or first send) fails for any reason, connectInternal wraps the underlying error into ChromaUnavailableError with message 'chroma-mcp connection failed: <cause>' so all connect failures take the reconnect-backoff / skip-the-write path instead of surfacing a raw error (e.g. a bare 'Error: Not connected' from a mid-handshake crash).","triggerScenarios":"Calling ensureConnected/connectInternal when the uvx chroma-mcp subprocess fails to start, dies during MCP handshake, times out, or the transport send throws because the subprocess exited mid-initialization.","commonSituations":"Incompatible or broken uvx/Chroma versions, Python env issues under uvx, corrupted local Chroma data directory, resource exhaustion killing the subprocess, or a connection timeout on a slow machine.","solutions":["Look at the wrapped cause after 'chroma-mcp connection failed:' and in logs (recordChromaVectorSearchUnavailable) for the root error.","Run `uvx chroma-mcp --help` manually to reproduce and see the subprocess's own error output.","Update uv/uvx and the chroma-mcp package to compatible versions.","Inspect/repair or move aside the local persistent Chroma data directory if it is corrupted.","Retry after the reconnect backoff; transient crashes and timeouts often recover."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  await manager.ensureConnected();\n} catch (e) {\n  if (e instanceof ChromaUnavailableError && e.message.startsWith('chroma-mcp connection failed')) {\n    logger.warn('chroma-mcp unavailable, skipping write', { cause: e.cause ?? e.message });\n    queueWriteForRetry();\n  } else throw e;\n}","preventionTips":["Keep uv/uvx and chroma-mcp versions compatible and updated.","Test `uvx chroma-mcp` manually after environment or version changes.","Watch logs for repeated handshake failures indicating a corrupted local Chroma data directory.","Allow the reconnect backoff to work; do not bypass it with aggressive retries."],"tags":["chroma","mcp","connection","subprocess"],"backgroundTag":"connection-refused","analyzedSha":"d8bc9755e74915e5c3b999181e10a67c889bce2a","analyzedAt":"2026-09-17T16:40:26.182Z","contentChangedAt":"2026-09-17T16:40:26.182Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}