chroma-core/chroma · error · ChromaClientError
Unprocessable Entity: ${response.statusText}
Error message
Unprocessable Entity: ${response.statusText} What it means
Thrown by chromaFetch (chroma-fetch.ts:127) as a ChromaClientError when the server returns 422 and even reading/parsing the body fails (response.json() throws and the caught error is not already a Chroma error). The message is synthesized as 'Unprocessable Entity: <statusText>', meaning content-level rejection with an unreadable body — typically an HTML error page from a proxy rather than Chroma's JSON.
Source
Thrown at clients/new-js/packages/chromadb/src/chroma-fetch.ts:127
try {
const body = await response.json();
if (
body &&
body.message &&
(body.message.startsWith("Quota exceeded") ||
body.message.startsWith("Billing limit exceeded"))
) {
throw new ChromaQuotaExceededError(body?.message);
}
throw new ChromaClientError(body?.message || "Unprocessable Entity");
} catch (error) {
if (
error instanceof ChromaQuotaExceededError ||
error instanceof ChromaClientError
) {
throw error;
}
throw new ChromaClientError(
`Unprocessable Entity: ${response.statusText}`,
);
}
case 429:
const rateLimitBody = await getErrorBody(response);
if (rateLimitBody.error === "Backoff") {
throw new ChromaBackoffError(
rateLimitBody.message || "Backoff and retry",
);
}
throw new ChromaRateLimitError("Rate limit exceeded");
}
const errorMessage = await getErrorMessage(response);
throw new ChromaServerError(errorMessage);
};
View on GitHub (pinned to aecdd12c8a)
Solutions
- Bypass the proxy temporarily (hit the Chroma port directly) to confirm the 422 originates from Chroma itself.
- Check proxy/WAF logs and rules — especially request-size limits and body validation that can emit 422.
- Shrink the request batch size if large payloads trip the proxy.
- Reproduce with curl through the same proxy to capture the actual body.
Example fix
# before: nginx WAF returns HTML 422 for large batches
await collection.add(bigBatch); // 'Unprocessable Entity: ...'
# after: chunk the payload so it passes the proxy
for (const chunk of chunkBatch(bigBatch, 5000)) {
await collection.add(chunk);
} Defensive patterns
Strategy: try-catch
Validate before calling
const MAX_BODY = 4 * 1024 * 1024; // keep under proxy body limits
if (JSON.stringify(batch).length > MAX_BODY) {
throw new Error("batch too large for proxy; split before sending");
} Try / catch
try {
await collection.add(batch);
} catch (e) {
if (e instanceof ChromaClientError && e.message.startsWith("Unprocessable Entity:")) {
// body was not JSON: suspect proxy/WAF interception; curl through the same hop to confirm
}
throw e;
} Prevention
- Point clients directly at the Chroma service port, or whitelist it in WAF/proxy rules.
- Keep request bodies well under proxy size limits by batching conservatively.
- Capture proxy access logs alongside app logs to attribute 422s to the right tier.
When it happens
Trigger: A reverse proxy (nginx, ingress, Cloudflare) in front of Chroma intercepting the request and returning a 422 HTML/text page; truncated responses; content-encoding corruption making the body unparseable.
Common situations: Self-hosted Chroma behind an API gateway with body-validation WAF rules; proxies rejecting large embedding payloads; middleboxes mangling responses.
Related errors
- {resp.text} (trace ID: {trace_id})
- Error calling Jina AI API: ${error.message}
- Failed to connect to Chroma
- Quota exceeded
- Unprocessable Entity
AI-assisted analysis of chroma-core/chroma@aecdd12c8a (2026-08-16).
Data as JSON: /api/errors/fd8c60c5837e766d.
Report an issue: GitHub.