chroma-core/chroma · error · ValueError
max_retries must be a non-negative integer
Error message
max_retries must be a non-negative integer
What it means
`collection.transaction.run(callback, max_retries=...)` validates max_retries up front: it must be a Python int and >= 0 (bools also fail the value path since True==1 is int but a float or string is not). The value bounds how many times run() retries the whole callback on ConditionalWriteConflictError, StaleReadError, or BackoffError.
Source
Thrown at chromadb/api/models/ConditionalCollectionTransaction.py:38
Where,
WhereDocument,
)
if TYPE_CHECKING:
from chromadb.api.models.Collection import Collection
T = TypeVar("T")
_RUN_RETRYABLE_ERRORS = (
ConditionalWriteConflictError,
StaleReadError,
BackoffError,
)
def _validate_max_retries(max_retries: int) -> None:
if not isinstance(max_retries, int) or max_retries < 0:
raise ValueError("max_retries must be a non-negative integer")
class ConditionalCollectionTransaction:
"""Collection-scoped optimistic transaction.
Reads execute immediately and capture the transaction snapshot. Writes are
buffered locally until ``commit()`` or until ``run(...)`` commits after a
successful callback.
Current limitations: transactions cannot span collections, nested
transaction guarantees are not provided, ``txn.query(...)`` and predicate
deletes are not supported, reading an ID after buffering a write for that
ID is an explicit transaction error, only one write per ID can be buffered,
and filter reads protect only returned IDs.
"""
def __init__(self, collection: "Collection") -> None:
self._collection = collectionView on GitHub (pinned to aecdd12c8a)
Solutions
- Pass a non-negative int: `txn.run(cb, max_retries=5)`
- Coerce external config: `max_retries = int(max_retries)` and validate the range at load time
- If unlimited retries are wanted, pick an explicit high bound — 'infinite' is not supported
Example fix
# before
retries = os.environ.get("TXN_RETRIES", "3") # str
txn.run(work, max_retries=retries) # ValueError (str)
txn.run(work, max_retries=-1) # ValueError (negative)
# after
retries = int(os.environ.get("TXN_RETRIES", "3"))
assert retries >= 0
txn.run(work, max_retries=retries) Defensive patterns
Strategy: validation
Validate before calling
max_retries = int(max_retries) if str(max_retries).isdigit() else 3
if not isinstance(max_retries, int) or max_retries < 0:
raise ValueError("max_retries must be a non-negative int")
txn.run(work, max_retries=max_retries) Type guard
def is_valid_max_retries(v) -> bool:
return isinstance(v, int) and not isinstance(v, bool) and v >= 0 Prevention
- Parse retry settings from config/env into ints at load time with range validation
- Do not use -1 for infinite retries — pick an explicit bound
- Keep max_retries modest (e.g. 3-5); each retry re-runs the whole callback
When it happens
Trigger: `txn.run(cb, max_retries=-1)`, `max_retries=1.5`, `max_retries="3"`, or `max_retries=None` — typically from config/env parsing that did not coerce to int.
Common situations: Reading retry counts from environment variables or YAML (arrive as strings), or using -1 as an 'infinite retries' sentinel from another library's convention.
Related errors
- Invalid URL. Unrecognized protocol - {parsed.scheme}.
- Invalid URL. Seems that you are trying to pass URL as a host
- ids must be provided for transactional delete
- ids must be provided for transactional delete
- Cannot specify both 'hnsw' and 'spann' configurations during
AI-assisted analysis of chroma-core/chroma@aecdd12c8a (2026-08-16).
Data as JSON: /api/errors/6968faf9a657a4ea.
Report an issue: GitHub.