chroma-core/chroma · error · ValueError
Unequal lengths for fields: {error_str}
Error message
Unequal lengths for fields: {error_str} What it means
Chroma validates every batch write (add/upsert/update) client-side before any data reaches storage. It normalizes all list arguments (ids, embeddings, metadatas, documents, images, uris) into a record set, and _validate_record_set_length_consistency (chromadb/api/types.py:450, called from validate_insert_record_set) requires every provided list to have the same length. When two or more provided lists disagree, it raises this error with a per-field length report so you can see exactly which lists are out of sync.
Source
Thrown at chromadb/api/types.py:473
f"At least one of one of {', '.join(record_set.keys())} must be provided"
)
zero_lengths = [
key
for key, lst in record_set.items()
if lst is not None and len(lst) == 0 # type: ignore[arg-type]
]
if zero_lengths:
raise ValueError(f"Non-empty lists are required for {zero_lengths}")
if len(set(lengths)) > 1:
error_str = ", ".join(
f"{key}: {len(lst)}"
for key, lst in record_set.items()
if lst is not None # type: ignore[arg-type]
)
raise ValueError(f"Unequal lengths for fields: {error_str}")
def validate_record_set_for_embedding(
record_set: BaseRecordSet, embeddable_fields: Optional[Set[str]] = None
) -> None:
"""
Validates that the Record is ready to be embedded, i.e. that it contains exactly one of the embeddable fields.
"""
if record_set["embeddings"] is not None:
raise ValueError("Attempting to embed a record that already has embeddings.")
if embeddable_fields is None:
embeddable_fields = get_default_embeddable_record_set_fields()
validate_record_set_contains_one(record_set, embeddable_fields)
def validate_record_set_contains_any(
record_set: BaseRecordSet, contains_any: Set[str]
) -> None:View on GitHub (pinned to aecdd12c8a)
Solutions
- Make every provided list the same length as ids (the message lists each field with its length - align the offenders first)
- Add an assert before the call: assert len(ids) == len(documents) == len(metadatas)
- Build a single list of record dicts and derive each column from it (ids=[r['id'] for r in records], documents=[r['text'] for r in records]) so lengths cannot diverge
- When sourcing from a dataframe, slice the frame once (df = df.head(n)) and then read each column
Example fix
# before
collection.add(ids=ids, documents=docs, metadatas=metas) # lengths drifted apart
# after
assert len(ids) == len(docs) == len(metas), f'{len(ids)} vs {len(docs)} vs {len(metas)}'
collection.add(ids=ids, documents=docs, metadatas=metas) Defensive patterns
Strategy: validation
Validate before calling
def assert_batch_lengths(ids, **fields):
n = len(ids)
bad = {name: len(v) for name, v in fields.items() if v is not None and len(v) != n}
if bad:
raise ValueError(f'Length mismatch vs ids({n}): {bad}')
assert_batch_lengths(ids, documents=docs, metadatas=metas, embeddings=embs)
collection.add(ids=ids, documents=docs, metadatas=metas, embeddings=embs) Type guard
def batch_is_consistent(ids, **fields) -> bool:
return all(v is None or len(v) == len(ids) for v in fields.values()) Try / catch
try:
collection.add(ids=ids, documents=docs, metadatas=metas)
except ValueError as e:
if 'Unequal lengths for fields' in str(e):
logger.error('batch column drift', extra={'lens': {k: len(v) for k, v in [('ids', ids), ('documents', docs), ('metadatas', metas)]}})
raise Prevention
- Derive every column from a single list of record dicts so lengths cannot diverge
- Assert lengths in debug builds or CI fixtures
- Slice dataframes once, then read columns
- Log per-column lengths before each batch write
When it happens
Trigger: collection.add(ids=['a','b','c'], documents=['only-one']) (3 ids vs 1 document); upsert where metadatas came from df.head(10) but ids has 25 entries; update where embeddings has a different count than ids; passing one scalar argument (auto-wrapped to length 1 by maybe_cast_one_to_many) alongside N ids, e.g. add(ids=[...], documents='single doc').
Common situations: Building ids/documents/metadatas in separate loops or comprehensions that drift out of sync; slicing a dataframe per column with different limits (df['id'][:200] vs df['text'][:100]); concatenating partial batches; off-by-one range() bugs; precomputed embedding arrays sized for a different batch.
Related errors
- Attempting to embed a record that already has embeddings.
- At least one of {', '.join(contains_any)} must be provided
- Exactly one of {', '.join(contains_one)} must be provided
- Invalid field in contains: {', '.join(contains)}, available
- Expected IDs to be a list, got {type(ids).__name__} as IDs
AI-assisted analysis of chroma-core/chroma@aecdd12c8a (2026-08-16).
Data as JSON: /api/errors/a6a1da9e247fc67c.
Report an issue: GitHub.