chroma-core/chroma · error · ValueError

Expected metadata to be a non-empty dict, got {len(metadata)

Error message

Expected metadata to be a non-empty dict, got {len(metadata)} metadata attributes

What it means

In the insert path (add/upsert and collection.modify) an empty dict {} is not valid metadata - Chroma treats it as an invalid input rather than 'no metadata'. validate_metadata raises as soon as one record's metadata is {}. Use None per record to express 'this record has no metadata'; omit the argument entirely when no record has any.

Source

Thrown at chromadb/api/types.py:1078

    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():
        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(

View on GitHub (pinned to aecdd12c8a)

Solutions

  1. Convert empty dicts to None: metadatas=[m if m else None for m in metadatas]
  2. Omit the metadatas argument when no record carries metadata
  3. Build metadata dicts conditionally so empty ones are never constructed

Example fix

# before
collection.add(ids=ids, metadatas=[row_to_meta(r) for r in rows])  # some are {}

# after
collection.add(ids=ids, metadatas=[row_to_meta(r) or None for r in rows])
Defensive patterns

Strategy: validation

Validate before calling

metadatas = [m if m else None for m in metadatas]
collection.add(ids=ids, metadatas=metadatas)

Type guard

def has_no_empty_metadata_dicts(metadatas) -> bool:
    return all(m is None or len(m) > 0 for m in metadatas if m is not None) and all(m is None or isinstance(m, dict) for m in metadatas)

Try / catch

try:
    collection.add(ids=ids, metadatas=metas)
except ValueError as e:
    if 'non-empty dict' in str(e):
        collection.add(ids=ids, metadatas=[m or None for m in metas])
    else:
        raise

Prevention

When it happens

Trigger: collection.add(ids=..., metadatas=[{}, {'k': 1}]); a dataframe metadata column where some rows produce row.to_dict() == {}; collection.modify(metadata={}) attempting to send empty collection metadata.

Common situations: row.to_dict() on rows without attributes; default {} instead of None in ingestion code; attempting to 'clear' metadata by passing an empty dict instead of omitting the key.

Related errors


AI-assisted analysis of chroma-core/chroma@aecdd12c8a (2026-08-16). Data as JSON: /api/errors/56a3cf9124046f11. Report an issue: GitHub.