{"record":{"id":"d14ba6fc4680fd69","repo":"chroma-core/chroma","slug":"expected-metadata-list-value-for-key-key-to-be","errorCode":null,"errorMessage":"Expected metadata list value for key '{key}' to be non-empty","messagePattern":"Expected metadata list value for key '(.+?)' to be non-empty","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"chromadb/api/types.py","lineNumber":1053,"sourceCode":"            )\n        else:\n            examples = []\n            for idx, dup in enumerate(dups):\n                examples.append(dup)\n                if idx == 10:\n                    break\n            example_string = (\n                f\"{', '.join(examples[:5])}, ..., {', '.join(examples[-5:])}\"\n            )\n            message = f\"Expected IDs to be unique, found {n_dups} duplicated IDs: {example_string}\"\n        raise errors.DuplicateIDError(message)\n    return ids\n\n\ndef _validate_metadata_list_value(key: str, value: list) -> None:\n    \"\"\"Validates a list metadata value: must be non-empty and homogeneously typed.\"\"\"\n    if len(value) == 0:\n        raise ValueError(\n            f\"Expected metadata list value for key '{key}' to be non-empty\"\n        )\n    first_type = type(value[0])\n    # Normalize: bool must be checked before int since isinstance(True, int) is True\n    if isinstance(value[0], bool):\n        first_type = bool\n    for item in value:\n        item_type = bool if isinstance(item, bool) else type(item)\n        if item_type is not first_type or item_type not in (str, int, float, bool):\n            raise ValueError(\n                f\"Expected metadata list value for key '{key}' to contain only str, int, float, or bool \"\n                f\"and all elements must be the same type, got {value}\"\n            )\n\n\ndef validate_metadata(metadata: Metadata) -> Metadata:\n    \"\"\"Validates metadata to ensure it is a dictionary of strings to strings, ints, floats, bools, SparseVectors, or lists thereof\"\"\"\n    if not isinstance(metadata, dict) and metadata is not None:","sourceCodeStart":1035,"sourceCodeEnd":1071,"githubUrl":"https://github.com/chroma-core/chroma/blob/aecdd12c8a891610db8653630b066b32ceb678b5/chromadb/api/types.py#L1035-L1071","documentation":"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'.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Use None instead of [] for 'no value': {'tags': None} is valid metadata","Strip empty lists before sending: {k: v for k, v in meta.items() if v != []}","In ETL, map empty iterables to None at the metadata-building step"],"exampleFix":"# before\nmeta = {'tags': [t for t in row['tags'] if keep(t)]}  # may be []\n\n# after\nmeta = {'tags': [t for t in row['tags'] if keep(t)] or None}","handlingStrategy":"validation","validationCode":"def clean_empty_lists(meta):\n    return {k: (None if isinstance(v, list) and len(v) == 0 else v) for k, v in meta.items()}\n\nmetadatas = [clean_empty_lists(m) for m in metadatas]","typeGuard":"def has_no_empty_list_values(meta) -> bool:\n    return not any(isinstance(v, list) and len(v) == 0 for v in meta.values())","tryCatchPattern":"try:\n    collection.add(ids=ids, metadatas=metas)\nexcept ValueError as e:\n    if 'to be non-empty' in str(e):\n        metas = [clean_empty_lists(m) for m in metas]\n        collection.add(ids=ids, metadatas=metas)\n    else:\n        raise","preventionTips":["Represent 'no value' lists as None, never []","Map empty iterables to None during ETL metadata building","Unit-test metadata builders against rows with missing list fields"],"tags":["chromadb","python","metadata","lists","validation"],"backgroundTag":"empty-list-metadata","analyzedSha":"aecdd12c8a891610db8653630b066b32ceb678b5","analyzedAt":"2026-08-16T21:53:27.228Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}