{"record":{"id":"79adb91414ecd332","repo":"chroma-core/chroma","slug":"ids-must-be-provided-for-transactional-delete","errorCode":null,"errorMessage":"ids must be provided for transactional delete","messagePattern":"ids must be provided for transactional delete","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"chromadb/api/models/AsyncConditionalCollectionTransaction.py","lineNumber":258,"sourceCode":"            self._collection._client._conditional_upsert(\n                transaction=self._transaction,\n                collection_id=self._collection.id,\n                ids=upsert_request[\"ids\"],\n                embeddings=upsert_request[\"embeddings\"],\n                metadatas=upsert_request[\"metadatas\"],\n                documents=upsert_request[\"documents\"],\n                uris=upsert_request[\"uris\"],\n                tenant=self._collection.tenant,\n                database=self._collection.database,\n            )\n        )\n\n    async def delete(self, ids: OneOrMany[ID]) -> None:\n        delete_request = self._collection._validate_and_prepare_delete_request(\n            ids, None, None\n        )\n        if delete_request[\"ids\"] is None:\n            raise ValueError(\"ids must be provided for transactional delete\")\n\n        await self._run_transaction_operation(\n            self._collection._client._conditional_delete(\n                transaction=self._transaction,\n                collection_id=self._collection.id,\n                ids=delete_request[\"ids\"],\n                tenant=self._collection.tenant,\n                database=self._collection.database,\n            )\n        )\n\n    async def commit(self) -> ConditionalCommitResult:\n        if self._commit_blocked_by_run:\n            raise ValueError(\"txn.commit() cannot be called inside run()\")\n        return await self._commit_after_run()\n","sourceCodeStart":240,"sourceCodeEnd":274,"githubUrl":"https://github.com/chroma-core/chroma/blob/aecdd12c8a891610db8653630b066b32ceb678b5/chromadb/api/models/AsyncConditionalCollectionTransaction.py#L240-L274","documentation":"Raised by AsyncConditionalCollectionTransaction.delete(). Conditional (optimistic) transactions only support delete-by-ID: the wrapper builds the delete request with where/where_document forced to None, then requires the validated 'ids' field to be non-None. Predicate deletes are an explicit limitation of the transaction API, so any ids value that unpacks to None is rejected before the server is called.","triggerScenarios":"Calling `await txn.delete(ids)` on a transaction obtained from an AsyncCollection where `ids` survives the 'at least one parameter' presence check but validates/unpacks to a None ids list (e.g. a None-equivalent or empty/malformed value passed through maybe_cast_one_to_many).","commonSituations":"Porting `collection.delete(where=...)` / `delete(where_document=...)` calls into `collection.transaction.run(...)`, or passing a variable that is None at runtime inside the run callback.","solutions":["Pass an explicit list of concrete string IDs: `await txn.delete([\"id-1\", \"id-2\"])`","If you need delete-by-filter, first `txn.get(where=..., include=[])` inside the transaction to collect IDs, then delete those IDs in the same transaction","If predicate semantics are required and transactional guarantees are not, use the non-transactional `collection.delete(where=..., where_document=...)`","Check the ids variable is a non-empty list before entering `run()`"],"exampleFix":"// before\nawait txn.delete(ids=None)  # or a variable that is None at runtime\n\n// after\nif not ids:\n    raise ValueError(\"cannot delete without ids inside a transaction\")\nawait txn.delete(ids=ids)","handlingStrategy":"validation","validationCode":"ids = [\"a\", \"b\"]\nif ids is None or len(list(ids)) == 0:\n    raise ValueError(\"transactional delete requires explicit non-empty ids\")\nawait txn.delete(ids=list(ids))","typeGuard":"from typing import Any, List, TypeGuard\n\ndef is_non_empty_id_list(v: Any) -> TypeGuard[List[str]]:\n    return isinstance(v, (list, tuple)) and len(v) > 0 and all(isinstance(i, str) for i in v)","tryCatchPattern":null,"preventionTips":["Never pass where/where_document semantics into txn.delete; transactions are delete-by-id only","Resolve filter-based deletes to an explicit id list with txn.get(where=..., include=[]) before deleting","Assert ids are non-empty right before the delete call inside the run callback"],"tags":["transactions","delete","input-validation","async"],"backgroundTag":"missing-required-parameter","analyzedSha":"aecdd12c8a891610db8653630b066b32ceb678b5","analyzedAt":"2026-08-16T21:53:27.228Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}