chroma-core/chroma · warning · ChromaStaleReadError

stale read

Error message

stale read

What it means

Thrown by chromaFetch (chroma-fetch.ts:101) as a ChromaStaleReadError when the server returns 412 and the body identifies a StaleReadError. It comes from Chroma's consistency controls: the read was issued with a session/consistency token older than what the server requires, so the server refuses to serve data that might violate the requested consistency level and asks the client to retry on a newer session.

Source

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

        `The requested resource could not be found`,
      );
    case 409:
      const conflictBody = await getErrorBody(response);
      if (
        conflictBody.error === "ConditionalWriteConflictError" ||
        conflictBody.message === "conditional write conflict"
      ) {
        throw new ChromaConditionalWriteConflictError(
          conflictBody.message || "conditional write conflict",
        );
      }
      throw new ChromaUniqueError(
        conflictBody.message || "The resource already exists",
      );
    case 412:
      const preconditionBody = await getErrorBody(response);
      if (preconditionBody.error === "StaleReadError") {
        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");

View on GitHub (pinned to aecdd12c8a)

Solutions

  1. Catch ChromaStaleReadError and retry the read after refreshing the session/token (re-obtain the collection handle or session from the server).
  2. Avoid caching session tokens across long idle periods; refresh them before read-after-write sequences.
  3. If strict consistency is not needed, perform the read without the session/consistency parameter.

Example fix

// before
const col = await client.getCollection({ name: "docs" }); // session token captured
await new Promise(r => setTimeout(r, 60000));
await col.query({ queryTexts: ["x"] }); // 412 StaleReadError if session advanced

// after
try {
  await col.query({ queryTexts: ["x"] });
} catch (e) {
  if (e instanceof ChromaStaleReadError) {
    const fresh = await client.getCollection({ name: "docs" });
    return fresh.query({ queryTexts: ["x"] });
  }
  throw e;
}
Defensive patterns

Strategy: retry

Try / catch

try {
  return await collection.query(args);
} catch (e) {
  if (e instanceof ChromaStaleReadError) {
    const fresh = await client.getCollection({ name: collection.name });
    return fresh.query(args); // session refreshed by re-fetch
  }
  throw e;
}

Prevention

When it happens

Trigger: Reads (get/query/count) sent with a previously obtained session token after the session advanced server-side; using a session-scoped client across a long idle period; explicitly requesting strong consistency with a stale token.

Common situations: Caching a session-scoped collection handle too long; pauses between write and read where the session expires; retrying an old request payload after newer writes have bumped the session.

Related errors


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