chroma-core/chroma · error · InvalidArgumentError

transactional add for id "{id}" requires a prior read provin

Error message

transactional add for id "{id}" requires a prior read proving the id is absent

What it means

Raised by _validate_write_precondition (chromadb/api/conditional_http.py:299) when a transactional add targets an id the transaction has not proven absent. The conditional transaction protocol is read-then-write: _known_absent is populated only by a prior id-based get (no where/where_document) inside the same transaction that did not return the id. This prevents blind inserts from racing with concurrent writes, since the commit's OCC check is anchored to the read set.

Source

Thrown at chromadb/api/conditional_http.py:299

        self._operations.append({"operation": operation, "payload": payload})

    def _validate_buffered_write(self, operation: str, ids: IDs) -> None:
        call_ids: Set[str] = set()
        for id in ids:
            if id in call_ids:
                raise InvalidArgumentError(
                    f'transactional write request contains duplicate id "{id}"'
                )
            call_ids.add(id)
            if id in self._buffered_write_ids:
                raise InvalidArgumentError(
                    f'transaction already has a buffered write for id "{id}"'
                )
            self._validate_write_precondition(operation, id)

    def _validate_write_precondition(self, operation: str, id: str) -> None:
        if operation == "add" and id not in self._known_absent:
            raise InvalidArgumentError(
                f'transactional add for id "{id}" requires a prior read '
                "proving the id is absent"
            )
        if operation == "update" and id not in self._known_present:
            raise InvalidArgumentError(
                f'transactional update for id "{id}" requires a prior read '
                "proving the id is present"
            )
        if operation == "delete" and id not in self._known_present:
            raise InvalidArgumentError(
                f'transactional delete for id "{id}" requires a prior read '
                "proving the id is present"
            )


def require_conditional_http_transaction(
    transaction: object,
) -> ConditionalHttpTransaction:

View on GitHub (pinned to aecdd12c8a)

Solutions

  1. Inside the same transaction, first do an id-based get (collection.get(ids=[...]) with no where/where_document), then add the ids that were not returned
  2. If you do not need insert-if-absent semantics, use upsert instead - it has no read precondition
  3. Ensure the read and the add use the same transaction instance

Example fix

# before
with client.transaction():
    collection.add(ids=["doc1"], embeddings=[emb])   # no prior read
# after
with client.transaction():
    existing = collection.get(ids=["doc1"])           # proves absence
    collection.add(ids=["doc1"], embeddings=[emb])
Defensive patterns

Strategy: validation

Validate before calling

def prove_absent(collection, ids):
    got = collection.get(ids=ids)          # id-based, no where filters
    return [i for i in ids if i not in set(got["ids"])]

absent = prove_absent(collection, new_ids)
# only add() ids proven absent, inside the same transaction

Try / catch

from chromadb.errors import InvalidArgumentError

try:
    collection.add(ids=["doc1"], embeddings=[emb])
except InvalidArgumentError as e:
    if "requires a prior read" in str(e):
        collection.get(ids=["doc1"])
        collection.add(ids=["doc1"], embeddings=[emb])
    else:
        raise

Prevention

When it happens

Trigger: Calling collection.add(ids=["doc1"], ...) inside a transaction without a preceding collection.get(ids=["doc1"]) in that same transaction; reading with a where filter first (which never marks ids absent); reading in a different or earlier transaction than the one used for the add.

Common situations: Porting non-transactional code that called add() directly; doing an existence check via get(where=...) or a query, which does not populate _known_absent; splitting read and write across two transaction objects.

Related errors


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