{"record":{"id":"ec5055917cb71206","repo":"thedotmack/claude-mem","slug":"chroma-mutation-queue-is-full-this-pendingmutat","errorCode":null,"errorMessage":"Chroma mutation queue is full (${this.pendingMutationCalls}/${this.maxPendingMutationCalls}); deferring \"${toolName}\" to a later backfill","messagePattern":"Chroma mutation queue is full \\((.+?)/(.+?)\\); deferring \"(.+?)\" to a later backfill","errorType":"exception","errorClass":"ChromaUnavailableError","httpStatus":null,"severity":"warning","filePath":"src/services/sync/ChromaMcpManager.ts","lineNumber":795,"sourceCode":"      if (parseError instanceof Error) {\n        logger.debug('CHROMA_MCP', 'Non-JSON response from tool, returning null', {\n          toolName,\n          textPreview: firstTextContent.text.slice(0, 100)\n        });\n      }\n      return null;\n    }\n  }\n\n  private async enqueueMutation<T>(operation: () => Promise<T>, toolName: string): Promise<T> {\n    if (this.pendingMutationCalls >= this.maxPendingMutationCalls) {\n      const message = `Chroma mutation queue is full (${this.pendingMutationCalls}/${this.maxPendingMutationCalls}); deferring \"${toolName}\" to a later backfill`;\n      logger.warn('CHROMA_MCP', message, {\n        toolName,\n        pendingMutations: this.pendingMutationCalls,\n        maxPendingMutations: this.maxPendingMutationCalls\n      });\n      throw new ChromaUnavailableError(message);\n    }\n\n    this.pendingMutationCalls += 1;\n    const enqueuedGeneration = this.connectionGeneration;\n    const run = this.mutationTail\n      .catch(() => undefined)\n      .then(async () => {\n        if (enqueuedGeneration !== this.connectionGeneration) {\n          throw new ChromaMcpConnectionCancelledError('queued chroma-mcp mutation cancelled during shutdown');\n        }\n        return operation();\n      });\n\n    this.mutationTail = run.then(() => undefined, () => undefined);\n\n    try {\n      return await run;\n    } finally {","sourceCodeStart":777,"sourceCodeEnd":813,"githubUrl":"https://github.com/thedotmack/claude-mem/blob/d768ba364302d12b76e69e4f021f0bb1d2d50ed6/src/services/sync/ChromaMcpManager.ts#L777-L813","documentation":"Thrown by enqueueMutation when a new mutation tool call would exceed the in-flight cap: pendingMutationCalls >= maxPendingMutationCalls. It is a ChromaUnavailableError (503) by design — the manager deliberately defers the overflow mutation to a later backfill rather than queuing unbounded work. The mutation is not lost; it will be reconciled by ChromaSync.ensureBackfilled on a subsequent run using watermarks.","triggerScenarios":"callTool is invoked for a mutation tool (matches CHROMA_MUTATION_TOOL_PATTERN) while serializeMutations is on, and pendingMutationCalls has already reached maxPendingMutationCalls because prior mutations are still running through the serialized mutationTail promise chain.","commonSituations":"A burst of indexing (many observations/summaries/prompts) arrives faster than chroma-mcp can apply them; chroma-mcp slow-down (disk/CPU) grows the queue; a backfill running in parallel with live ingestion saturates the queue.","solutions":["Treat the error as transient: the mutation will be applied by the next backfill pass, so it is safe to log and continue.","Reduce ingestion burstiness — batch/coalesce writes so fewer individual mutation calls are issued.","Raise maxPendingMutationCalls if your workload legitimately needs a deeper in-flight queue.","Investigate why chroma-mcp is slow (disk I/O, large collection) so the queue drains faster.","Ensure ensureBackfilled is scheduled periodically so deferred mutations actually get reconciled."],"exampleFix":"// before: caller treats full-queue 503 as a hard failure\nawait manager.callTool('chroma_upsert', args);\n// after: caller recognizes the deferral and relies on backfill\ntry { await manager.callTool('chroma_upsert', args); }\ncatch (e) { if (e instanceof ChromaUnavailableError && /mutation queue is full/.test(e.message)) { log.warn('deferred to backfill'); } else throw e; }","handlingStrategy":"fallback","validationCode":null,"typeGuard":"function isMutationQueueFull(e: unknown): boolean {\n  return e instanceof Error && /Chroma mutation queue is full.*deferring/i.test(e.message);\n}","tryCatchPattern":"try { await manager.callTool('chroma_upsert', args); }\ncatch (e) {\n  if (isMutationQueueFull(e)) { /* safe: backfill will reconcile later */ log.warn('mutation deferred to backfill'); return; }\n  throw e;\n}","preventionTips":["Coalesce bursty writes into fewer mutation calls to stay under maxPendingMutationCalls.","Schedule ensureBackfilled periodically so deferred mutations are reconciled.","Tune maxPendingMutationCalls to your steady-state ingestion rate.","Keep chroma-mcp healthy so the queue drains at full speed."],"tags":["chroma","mutation-queue","backpressure","backfill","vector-search"],"backgroundTag":null,"analyzedSha":"d768ba364302d12b76e69e4f021f0bb1d2d50ed6","analyzedAt":"2026-08-12T23:52:55.241Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}