chroma-core/chroma · warning · ChromaConditionalWriteConflictError

conditional write conflict

Error message

conditional write conflict

What it means

Thrown by chromaFetch (chroma-fetch.ts:91) as a ChromaConditionalWriteConflictError when the server returns 409 and the body identifies a ConditionalWriteConflictError. This is Chroma's optimistic-concurrency control: a write (add/upsert/update/delete) whose version precondition did not match the collection's current version lost the race against a concurrent writer, and the server rejected it so you can retry against the new state.

Source

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

        } with status: ${status}`,
      );
    case 401:
      throw new ChromaUnauthorizedError(`Unauthorized`);
    case 403:
      throw new ChromaForbiddenError(
        `You do not have permission to access the requested resource.`,
      );
    case 404:
      throw new ChromaNotFoundError(
        `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 {

View on GitHub (pinned to aecdd12c8a)

Solutions

  1. Catch ChromaConditionalWriteConflictError and retry the operation after re-reading the current collection version, ideally with jittered backoff.
  2. Reduce write contention by funnelting writes through a single writer/queue for the hot collection.
  3. Re-fetch the collection handle (to refresh its version) before each conditional write in long sessions.
  4. If you do not need OCC guarantees, drop the version precondition parameter.

Example fix

// before
await collection.upsert({ ids, documents, /* version: staleVersion */ }); // 409 conditional write conflict

// after
try {
  await collection.upsert({ ids, documents });
} catch (e) {
  if (e instanceof ChromaConditionalWriteConflictError) {
    await sleep(50 * (1 + Math.random()));
    return collection.upsert({ ids, documents }); // retry against fresh state
  }
  throw e;
}
Defensive patterns

Strategy: retry

Try / catch

for (let attempt = 0; ; attempt++) {
  try {
    return await collection.upsert(payload);
  } catch (e) {
    if (e instanceof ChromaConditionalWriteConflictError && attempt < 5) {
      await new Promise(r => setTimeout(r, 2 ** attempt * 50 + Math.random() * 100));
      continue; // optionally refresh collection version here
    }
    throw e;
  }
}

Prevention

When it happens

Trigger: Two concurrent writers mutating the same collection with version precondition headers (e.g. upsert with if-collection-version); long-running read-then-write sequences where the collection changed in between; high-concurrency ingestion pipelines using conditional writes.

Common situations: Parallel batch writers to one collection; retries after timeouts that actually succeeded server-side; cache of collection version kept too long before a conditional update.

Related errors


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