chroma-core/chroma · error · ValueError
Expected metadata to not contain the reserved key {META_KEY_
Error message
Expected metadata to not contain the reserved key {META_KEY_CHROMA_DOCUMENT} What it means
The key 'chroma:document' (constant META_KEY_CHROMA_DOCUMENT at chromadb/api/types.py:135) is reserved: Chroma stores each record's document text under this metadata key internally (notably to support sparse embeddings). validate_metadata rejects user metadata that claims it, preventing silent overwrites of Chroma's internal state. Keys under the 'chroma:' namespace generally should be treated as off-limits.
Source
Thrown at chromadb/api/types.py:1083
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():
if key == META_KEY_CHROMA_DOCUMENT:
raise ValueError(
f"Expected metadata to not contain the reserved key {META_KEY_CHROMA_DOCUMENT}"
)
if not isinstance(key, str):
raise TypeError(
f"Expected metadata key to be a str, got {key} which is a {type(key).__name__}"
)
# 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} which is a {type(value).__name__}"
)View on GitHub (pinned to aecdd12c8a)
Solutions
- Rename your key (e.g. 'source_document')
- Strip reserved keys when echoing data back: {k: v for k, v in m.items() if not k.startswith('chroma:')}
- Treat the chroma: namespace as reserved in your metadata schema from day one
Example fix
# before
new_meta = dict(old_meta) # old_meta may contain 'chroma:document'
# after
new_meta = {k: v for k, v in old_meta.items() if not k.startswith('chroma:')} Defensive patterns
Strategy: validation
Validate before calling
def strip_reserved_keys(meta):
return {k: v for k, v in meta.items() if not k.startswith('chroma:')}
metadatas = [strip_reserved_keys(m) for m in metadatas] Type guard
def is_user_metadata(meta) -> bool:
return all(not k.startswith('chroma:') for k in meta) Try / catch
try:
collection.add(ids=ids, metadatas=metas)
except ValueError as e:
if 'reserved key' in str(e):
collection.add(ids=ids, metadatas=[{k: v for k, v in m.items() if not k.startswith('chroma:')} for m in metas])
else:
raise Prevention
- Treat the chroma: namespace as reserved in your schema
- Sanitize metadata when round-tripping Chroma output back into add()
- Name custom internal fields with your own prefix, not chroma:
When it happens
Trigger: metadatas=[{'chroma:document': 'text'}] on add/upsert; update metadatas containing the key; round-tripping Chroma's own output back in - copying metadata from .get(include=['metadatas']) on a version that exposes the internal key and feeding it to add().
Common situations: Echoing Chroma results back into another collection; users choosing namespaced keys that collide with 'chroma:*'; tooling that reads internal storage formats and re-inserts rows.
Related errors
- Expected metadata list value for key '{key}' to be non-empty
- Expected metadata list value for key '{key}' to contain only
- Expected metadata to be a dict or None, got {type(metadata).
- Expected metadata to be a non-empty dict, got {len(metadata)
- Expected metadata key to be a str, got {key} which is a {typ
AI-assisted analysis of chroma-core/chroma@aecdd12c8a (2026-08-16).
Data as JSON: /api/errors/9635f31ef399c1b2.
Report an issue: GitHub.