chroma-core/chroma · error · ValueError

Expected metadata list value for key '{key}' to be non-empty

Error message

Expected metadata list value for key '{key}' to be non-empty

What it means

Chroma accepts list-valued metadata (e.g. {'tags': ['a','b']}) but the list must be non-empty: an empty list carries no filterable value and the storage layer cannot represent it. _validate_metadata_list_value (chromadb/api/types.py:1047) raises when the value is []. Note the asymmetry: scalar metadata values may be None, but list values may not be empty - use None to mean 'no value'.

Source

Thrown at chromadb/api/types.py:1053

            )
        else:
            examples = []
            for idx, dup in enumerate(dups):
                examples.append(dup)
                if idx == 10:
                    break
            example_string = (
                f"{', '.join(examples[:5])}, ..., {', '.join(examples[-5:])}"
            )
            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:

View on GitHub (pinned to aecdd12c8a)

Solutions

  1. Use None instead of [] for 'no value': {'tags': None} is valid metadata
  2. Strip empty lists before sending: {k: v for k, v in meta.items() if v != []}
  3. In ETL, map empty iterables to None at the metadata-building step

Example fix

# before
meta = {'tags': [t for t in row['tags'] if keep(t)]}  # may be []

# after
meta = {'tags': [t for t in row['tags'] if keep(t)] or None}
Defensive patterns

Strategy: validation

Validate before calling

def clean_empty_lists(meta):
    return {k: (None if isinstance(v, list) and len(v) == 0 else v) for k, v in meta.items()}

metadatas = [clean_empty_lists(m) for m in metadatas]

Type guard

def has_no_empty_list_values(meta) -> bool:
    return not any(isinstance(v, list) and len(v) == 0 for v in meta.values())

Try / catch

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

Prevention

When it happens

Trigger: collection.add(..., metadatas=[{'tags': []}]); collection.modify(metadata={'topics': []}); collection.update(ids=..., metadatas=[{'tags': []}]) - typically tag/genre/category fields where some records legitimately have no entries.

Common situations: Tag or genre columns where empty means 'none'; ETL that defaults missing lists to [] instead of None; user profiles with empty follower/interest lists from JSON sources.

Related errors


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