chroma-core/chroma · error · ValueError
Expected metadata list value for key '{key}' to contain only
Error message
Expected metadata list value for key '{key}' to contain only str, int, float, or bool and all elements must be the same type, got {value} What it means
List-valued metadata must be homogeneous: every element the same type, and only str, int, float or bool are allowed (bool is normalized before int because bool subclasses int). _validate_metadata_list_value raises with the full offending list when a list mixes types (['a', 1]), mixes int and float ([1, 1.5]), mixes bool with anything else, or contains non-scalars ([{'x':1}] or [[1]]).
Source
Thrown at chromadb/api/types.py:1063
message = f"Expected IDs to be unique, found {n_dups} duplicated IDs: {example_string}"
raise errors.DuplicateIDError(message)
return ids
def _validate_metadata_list_value(key: str, value: list) -> None:
"""Validates a list metadata value: must be non-empty and homogeneously typed."""
if len(value) == 0:
raise ValueError(
f"Expected metadata list value for key '{key}' to be non-empty"
)
first_type = type(value[0])
# Normalize: bool must be checked before int since isinstance(True, int) is True
if isinstance(value[0], bool):
first_type = bool
for item in value:
item_type = bool if isinstance(item, bool) else type(item)
if item_type is not first_type or item_type not in (str, int, float, bool):
raise ValueError(
f"Expected metadata list value for key '{key}' to contain only str, int, float, or bool "
f"and all elements must be the same type, got {value}"
)
def validate_metadata(metadata: Metadata) -> Metadata:
"""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).__name__} as metadata"
)
if metadata is None:
return metadata
if len(metadata) == 0:
raise ValueError(
f"Expected metadata to be a non-empty dict, got {len(metadata)} metadata attributes"
)
for key, value in metadata.items():View on GitHub (pinned to aecdd12c8a)
Solutions
- Coerce the whole list to one type at build time, e.g. [str(x) for x in vals] or [float(x) for x in vals]
- Drop the key (or set it to None) when the list cannot be homogenized
- Serialize non-conforming values (e.g. json.dumps) into a string field, noting Chroma filters on the whole list, not elements
- Add a unit test asserting each list field's element type before writes
Example fix
# before
meta = {'scores': row['scores']} # [1, 2.5, 3]
# after
meta = {'scores': [float(s) for s in row['scores']]} # homogeneous floats Defensive patterns
Strategy: type-guard
Validate before calling
ALLOWED = (str, int, float, bool)
def normalize_list_value(v):
if isinstance(v, list) and v:
ts = {bool if isinstance(x, bool) else type(x) for x in v}
if len(ts) == 1 and next(iter(ts)) in ALLOWED:
return v
return [str(x) for x in v] # coerce heterogeneous lists to str
return v Type guard
ALLOWED = (str, int, float, bool)
def is_homogeneous_scalar_list(v) -> bool:
if not isinstance(v, list) or not v:
return False
ts = {bool if isinstance(x, bool) else type(x) for x in v}
return len(ts) == 1 and next(iter(ts)) in ALLOWED Try / catch
try:
collection.add(ids=ids, metadatas=metas)
except ValueError as e:
if 'contain only str, int, float, or bool' in str(e):
metas = [{k: ([str(x) for x in val] if isinstance(val, list) else val) for k, val in m.items()} for m in metas]
collection.add(ids=ids, metadatas=metas)
else:
raise Prevention
- Coerce list fields to one type at build time ([str(x) for x in vals])
- Treat int/float mixes as floats uniformly
- Never store arrays of objects in metadata - serialize to a string field
When it happens
Trigger: metadatas=[{'vals': [1, 1.5]}] (int/float mix); {'tags': ['a', 1]}; {'flags': [True, 'yes']}; {'nested': [[1, 2]]} (list inside list); lists from schemaless JSON columns whose element types vary by row.
Common situations: MongoDB/JSON dumps where a field is usually strings but occasionally numbers; mixed bool/str flags from APIs; arrays of objects from webhooks; numeric pipelines emitting alternating int and float.
Related errors
- Expected metadata list value for key '{key}' to be non-empty
- Expected metadata value to be a str, int, float, bool, Spars
- Expected metadata value to be a str, int, float, bool, Spars
- Expected metadata to be a dict or None, got {type(metadata).
- Expected metadata to be a non-empty dict, got {len(metadata)
AI-assisted analysis of chroma-core/chroma@aecdd12c8a (2026-08-16).
Data as JSON: /api/errors/9ba00f416a08a350.
Report an issue: GitHub.