chroma-core/chroma · error · ValueError
Expected metadata to be a non-empty dict, got {metadata}
Error message
Expected metadata to be a non-empty dict, got {metadata} What it means
validate_update_metadata rejects {} as a per-record metadata on update (chromadb/api/types.py:1114, reached from collection.update via chromadb/segment.py:407). An empty update dict is treated as an invalid input rather than 'change nothing'. The correct way to express 'nothing to change' for a record is to omit it from the ids/metadatas lists, or use None as the element.
Source
Thrown at chromadb/api/types.py:1114
elif not isinstance(value, bool) and not isinstance(
value, (str, int, float, type(None))
):
raise ValueError(
f"Expected metadata value to be a str, int, float, bool, SparseVector, list, or None, got {value} which is a {type(value).__name__}"
)
return metadata
def validate_update_metadata(metadata: UpdateMetadata) -> UpdateMetadata:
"""Validates metadata to ensure it is a dictionary of strings to strings, ints, floats, bools, SparseVectors, or lists thereof"""
if not isinstance(metadata, dict) and metadata is not None:
raise ValueError(
f"Expected metadata to be a dict or None, got {type(metadata)}"
)
if metadata is None:
return metadata
if len(metadata) == 0:
raise ValueError(f"Expected metadata to be a non-empty dict, got {metadata}")
for key, value in metadata.items():
if not isinstance(key, str):
raise ValueError(f"Expected metadata key to be a str, got {key}")
# Check if value is a SparseVector (validation happens in __post_init__)
if isinstance(value, SparseVector):
pass # Already validated in SparseVector.__post_init__
elif isinstance(value, list):
_validate_metadata_list_value(key, value)
# isinstance(True, int) evaluates to True, so we need to check for bools separately
elif not isinstance(value, bool) and not isinstance(
value, (str, int, float, type(None))
):
raise ValueError(
f"Expected metadata value to be a str, int, float, bool, SparseVector, list, or None, got {value}"
)
return metadata
View on GitHub (pinned to aecdd12c8a)
Solutions
- Skip unchanged rows: only include ids whose metadata diff is non-empty
- Send None instead of {}: metadatas=[m if m else None for m in metadatas]
- Split the batch so only genuinely changed records are updated
Example fix
# before
collection.update(ids=all_ids, metadatas=[diff(r) for r in rows]) # some diffs are {}
# after
changed = [(i, d) for i, d in zip(all_ids, diffs) if d]
collection.update(ids=[i for i, _ in changed], metadatas=[d for _, d in changed]) Defensive patterns
Strategy: validation
Validate before calling
pairs = [(i, m) for i, m in zip(ids, metadatas) if m]
if pairs:
collection.update(ids=[i for i, _ in pairs], metadatas=[m for _, m in pairs]) Type guard
def has_no_empty_update_dicts(metadatas) -> bool:
return all(m is None or len(m) > 0 for m in metadatas) Try / catch
try:
collection.update(ids=ids, metadatas=metas)
except ValueError as e:
if 'non-empty dict' in str(e):
collection.update(ids=ids, metadatas=[m if m else None for m in metas])
else:
raise Prevention
- Update only rows with a non-empty diff; skip unchanged rows
- Use None per record to leave metadata untouched
- In CDC pipelines, drop no-op changes before batching
When it happens
Trigger: collection.update(ids=['a'], metadatas=[{}]); batch updates where some rows have no changed fields; diff-based update builders that emit {} for unchanged rows.
Common situations: Change-data-capture pipelines computing per-row diffs and producing empty dicts for unchanged rows; UI save handlers that send the whole object including empty metadata; generic update loops over all rows regardless of change.
Related errors
- Expected metadata to be a non-empty dict, got {len(metadata)
- Expected metadata to be a dict or None, got {type(metadata)}
- Expected metadata key to be a str, got {key}
- Expected metadata value to be a str, int, float, bool, Spars
- Expected metadata list value for key '{key}' to be non-empty
AI-assisted analysis of chroma-core/chroma@aecdd12c8a (2026-08-16).
Data as JSON: /api/errors/0412df4f52b42ea1.
Report an issue: GitHub.