{"record":{"id":"ba137f09f0023722","repo":"chroma-core/chroma","slug":"backoff-and-retry","errorCode":null,"errorMessage":"Backoff and retry","messagePattern":"Backoff and retry","errorType":"http","errorClass":"ChromaBackoffError","httpStatus":429,"severity":"warning","filePath":"clients/new-js/packages/chromadb/src/chroma-fetch.ts","lineNumber":134,"sourceCode":"        ) {\n          throw new ChromaQuotaExceededError(body?.message);\n        }\n        throw new ChromaClientError(body?.message || \"Unprocessable Entity\");\n      } catch (error) {\n        if (\n          error instanceof ChromaQuotaExceededError ||\n          error instanceof ChromaClientError\n        ) {\n          throw error;\n        }\n        throw new ChromaClientError(\n          `Unprocessable Entity: ${response.statusText}`,\n        );\n      }\n    case 429:\n      const rateLimitBody = await getErrorBody(response);\n      if (rateLimitBody.error === \"Backoff\") {\n        throw new ChromaBackoffError(\n          rateLimitBody.message || \"Backoff and retry\",\n        );\n      }\n      throw new ChromaRateLimitError(\"Rate limit exceeded\");\n  }\n\n  const errorMessage = await getErrorMessage(response);\n  throw new ChromaServerError(errorMessage);\n};\n","sourceCodeStart":116,"sourceCodeEnd":144,"githubUrl":"https://github.com/chroma-core/chroma/blob/aecdd12c8a891610db8653630b066b32ceb678b5/clients/new-js/packages/chromadb/src/chroma-fetch.ts#L116-L144","documentation":"Thrown by chromaFetch (chroma-fetch.ts:134) as a ChromaBackoffError when the server returns 429 with error === 'Backoff'. Chroma Cloud uses this signal for server-side throttling with an advisory component: the caller should stop hammering the endpoint and retry later, respecting any guidance in the message (e.g. suggested wait).","triggerScenarios":"Sustained high-rate ingestion or querying against Chroma Cloud where the service sheds load; fan-out workers all retrying simultaneously after a slowdown; bursts exceeding the tenant's throughput class.","commonSituations":"Bulk backfills without rate limiting; retry storms after a transient slowdown; too many concurrent workers on one tenant.","solutions":["Catch ChromaBackoffError and retry with exponential backoff plus jitter; honor any wait guidance in the message.","Throttle the producer (p-limit, token bucket) so issuance stays under the throttle threshold.","Reduce concurrency of workers sharing one API key/tenant.","If sustained throughput is required, contact Chroma Cloud about raising the tenant's limits."],"exampleFix":"// before\nconst results = await Promise.all(docs.map(d => collection.add([d]))); // 429 Backoff\n\n// after\nimport pLimit from \"p-limit\";\nconst limit = pLimit(5);\nawait Promise.all(docs.map(d => limit(() => collection.add([d]))));\n// plus: on ChromaBackoffError, sleep with exponential backoff + jitter before retrying","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"for (let attempt = 0; ; attempt++) {\n  try {\n    return await operation();\n  } catch (e) {\n    if (e instanceof ChromaBackoffError && attempt < 8) {\n      await new Promise(r => setTimeout(r, Math.min(2 ** attempt * 500, 30_000) + Math.random() * 500));\n      continue;\n    }\n    throw e;\n  }\n}","preventionTips":["Run all Cloud calls through a single retry helper with exponential backoff + jitter.","Limit concurrency (p-limit) and pace producers below throttle thresholds.","Instrument ChromaBackoffError rates to detect undersized throughput limits early."],"tags":["http-429","rate-limit","throttling","retryable","cloud"],"backgroundTag":"rate-limit-backoff","analyzedSha":"aecdd12c8a891610db8653630b066b32ceb678b5","analyzedAt":"2026-08-16T21:53:27.228Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}