chroma-core/chroma · error · ChromaClientError

Unprocessable Entity

Error message

Unprocessable Entity

What it means

Thrown by chromaFetch (chroma-fetch.ts:119) as a ChromaClientError when the server returns 422, the JSON body parses, but it carries no usable `message` field and none of the quota/billing prefixes match. The server rejected the request as semantically invalid (well-formed but unacceptable content), and the library falls back to the bare status text.

Source

Thrown at clients/new-js/packages/chromadb/src/chroma-fetch.ts:119

        throw new ChromaStaleReadError(
          preconditionBody.message || "stale read",
        );
      }
      throw new ChromaClientError(
        preconditionBody.message || "Precondition Failed",
      );
    case 422:
      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",
        );
      }

View on GitHub (pinned to aecdd12c8a)

Solutions

  1. Inspect the raw response by reproducing the request with curl to see the server's full 422 body.
  2. Align client and server versions so error payloads and API contracts match.
  3. Validate payload invariants client-side (equal-length ids/documents/embeddings/metadata arrays, valid metadata value types).
  4. Check the collection's embedding configuration against the data you send.

Example fix

// before
await collection.add({ ids: ["1", "2"], documents: ["only-one"] }); // length mismatch => 422

// after
await collection.add({ ids: ["1", "2"], documents: ["first", "second"] });
Defensive patterns

Strategy: validation

Validate before calling

function assertBatchShape(b: { ids: string[]; documents?: string[]; embeddings?: number[][]; metadatas?: object[] }) {
  const n = b.ids.length;
  if (b.documents && b.documents.length !== n) throw new Error("documents length mismatch");
  if (b.embeddings && b.embeddings.length !== n) throw new Error("embeddings length mismatch");
  if (b.metadatas && b.metadatas.length !== n) throw new Error("metadatas length mismatch");
}

Try / catch

try {
  await collection.add(batch);
} catch (e) {
  if (e instanceof ChromaClientError && e.message === "Unprocessable Entity") {
    // server gave no message: reproduce with curl to read the raw 422 body
  }
  throw e;
}

Prevention

When it happens

Trigger: Semantic validation failures server-side: invalid embedding function configuration, malformed metadata values, inconsistent document/embedding array lengths, or any 422 whose error body uses a different shape than {message}.

Common situations: Version skew where an older server emits differently shaped 422 bodies; hand-built payloads skipping required fields; custom server middleware returning 422 without a message.

Related errors


AI-assisted analysis of chroma-core/chroma@aecdd12c8a (2026-08-16). Data as JSON: /api/errors/67b09c4d4d613c56. Report an issue: GitHub.