{"record":{"id":"8b1bc75ad4bbc78b","repo":"thedotmack/claude-mem","slug":"chroma-query-failed-errorobj-message","errorCode":null,"errorMessage":"Chroma query failed: ${errorObj.message}","messagePattern":"Chroma query failed: (.+?)","errorType":"exception","errorClass":"ChromaUnavailableError","httpStatus":null,"severity":"error","filePath":"src/services/worker/search/SearchOrchestrator.ts","lineNumber":68,"sourceCode":"    options: NormalizedParams\n  ): Promise<StrategySearchResult> {\n    if (!options.query) {\n      logger.debug('SEARCH', 'Orchestrator: Filter-only query, using SQLite', {});\n      return await this.sqliteStrategy.search(options);\n    }\n\n    if (this.chromaStrategy) {\n      logger.debug('SEARCH', 'Orchestrator: Using Chroma semantic search', {});\n      try {\n        const chromaResult = await this.chromaStrategy.search(options);\n        if (this.isEmptyResult(chromaResult)) {\n          logger.debug('SEARCH', 'Orchestrator: Chroma search returned zero matches; falling back to SQLite', {});\n          return await this.sqliteStrategy.search(options);\n        }\n        return chromaResult;\n      } catch (error) {\n        const errorObj = error instanceof Error ? error : new Error(String(error));\n        throw new ChromaUnavailableError(\n          `Chroma query failed: ${errorObj.message}`,\n          errorObj\n        );\n      }\n    }\n\n    logger.debug('SEARCH', 'Orchestrator: Chroma not configured', {});\n    return {\n      results: { observations: [], sessions: [], prompts: [] },\n      usedChroma: false,\n      strategy: 'sqlite'\n    };\n  }\n\n  private isEmptyResult(result: StrategySearchResult): boolean {\n    return result.results.observations.length === 0\n      && result.results.sessions.length === 0\n      && result.results.prompts.length === 0;","sourceCodeStart":50,"sourceCodeEnd":86,"githubUrl":"https://github.com/thedotmack/claude-mem/blob/d8bc9755e74915e5c3b999181e10a67c889bce2a/src/services/worker/search/SearchOrchestrator.ts#L50-L86","documentation":"The search orchestrator wraps any failure from the Chroma (vector) search strategy in a ChromaUnavailableError carrying the original message, so callers can distinguish 'Chroma is down/broken' from 'no results'. Note the orchestrator already falls back to SQLite only when Chroma returns zero matches — a thrown error propagates instead of falling back.","triggerScenarios":"Chroma HTTP query fails: Chroma server not running, connection refused, malformed query embedding, Chroma returning 4xx/5xx, or any non-Error thrown value in the chroma search path.","commonSituations":"Chroma subprocess (managed via uv/python) failed to start or crashed; port mismatch or stale CHROMA endpoint config after an upgrade; empty/corrupt chroma index directory; embedding dimension mismatch between index and query model.","solutions":["Check that the Chroma service is running and reachable (process, port, health endpoint)","Catch ChromaUnavailableError at the call site and fall back to the SQLite strategy, mirroring the zero-match fallback","Inspect the cause property (the wrapped original error) for the real failure — connection refused vs HTTP error vs embedding failure","Verify the chroma index and embedding configuration are intact and dimensionally consistent"],"exampleFix":"// before\nconst results = await orchestrator.search(options); // throws if Chroma errors\n// after\nlet results;\ntry {\n  results = await orchestrator.search(options);\n} catch (err) {\n  if (err instanceof ChromaUnavailableError) {\n    results = await sqliteStrategy.search(options); // graceful degradation\n  } else {\n    throw err;\n  }\n}","handlingStrategy":"fallback","validationCode":"import { existsSync } from 'fs';\n// quick health check before issuing vector searches:\nconst chromaUp = existsSync(chromaDataDir); // plus a real ping/health call to the Chroma endpoint in production","typeGuard":"function isChromaUnavailable(err: unknown): err is ChromaUnavailableError {\n  return err instanceof ChromaUnavailableError;\n}","tryCatchPattern":"try {\n  results = await orchestrator.search(options);\n} catch (err) {\n  if (isChromaUnavailable(err)) {\n    logger.warn('Chroma unavailable, falling back to SQLite', { cause: err.cause?.message });\n    results = await sqliteStrategy.search(options);\n  } else {\n    throw err;\n  }\n}","preventionTips":["Monitor the Chroma process/endpoint health and restart it on failure","Always keep the SQLite strategy warm as a degradation path","Inspect ChromaUnavailableError.cause for the real root cause before changing config","Verify embedding dimensions and index integrity after model or Chroma version upgrades"],"tags":["vector-search","chroma","fallback"],"backgroundTag":"http-request-failed","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"}