{"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":891,"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":873,"sourceCodeEnd":909,"githubUrl":"https://github.com/thedotmack/claude-mem/blob/d8bc9755e74915e5c3b999181e10a67c889bce2a/src/services/sync/ChromaMcpManager.ts#L873-L909","documentation":"ChromaMcpManager throttles mutation calls (add/update/delete to Chroma) through a serialized queue with a bounded number of pending operations. When pendingMutationCalls reaches maxPendingMutationCalls, further mutations are rejected with ChromaUnavailableError so they can be deferred to a later backfill instead of overwhelming the Chroma MCP server. This is deliberate backpressure, not a fault in the caller.","triggerScenarios":"Calling any Chroma mutation via ChromaMcpManager while maxPendingMutationCalls mutations are already queued awaiting the serialized mutationTail promise; typically bursts of writes during heavy sync activity.","commonSituations":"Bulk document ingest during initial backfill, rapid re-indexing after schema changes, or a slow/unresponsive Chroma MCP server causing queued mutations to pile up faster than they drain.","solutions":["Wait for the in-flight queue to drain and retry the mutation; the deferred work is covered by a later backfill.","Reduce concurrent producers of Chroma mutations (batch writes, serialize sync workers).","Check Chroma MCP server health/latency; a slow server makes the bounded queue fill quickly.","Raise maxPendingMutationCalls only if the Chroma server can absorb the extra load.","Ensure a backfill pass runs afterwards (ChromaSync.ensureBackfilled) so deferred mutations are applied."],"exampleFix":"// before: fire-and-forget bulk mutation loop\nfor (const doc of docs) await manager.mutate('add', doc);\n// after: chunk and retry on ChromaUnavailableError\nfor (const chunk of chunked(docs, 100)) {\n  await Promise.all(chunk.map(d => manager.mutate('add', d).catch(e => {\n    if (e instanceof ChromaUnavailableError) deferred.push(d); else throw e;\n  })));\n  await backfillIfDeferred();\n}","handlingStrategy":"retry","validationCode":"// before calling a mutation\nif (manager.getPendingMutationCount() >= manager.maxPendingMutationCalls) {\n  await drainOrDeferToBackfill();\n}","typeGuard":null,"tryCatchPattern":"try {\n  await manager.mutate('add', doc);\n} catch (e) {\n  if (e instanceof ChromaUnavailableError && /queue is full/.test(e.message)) {\n    deferredDocs.push(doc); // re-applied by later backfill\n  } else throw e;\n}","preventionTips":["Batch and pace Chroma mutation bursts instead of issuing them all at once","Monitor pendingMutationCalls and apply backpressure to producers early","Keep the Chroma MCP server healthy so the queue drains fast","Run periodic backfill so deferred mutations are never lost"],"tags":["backpressure","queue-limit","chroma"],"backgroundTag":"queue-backpressure-full","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"}