chroma-core/chroma · error · ValueError

Expected documents to be a list, got {type(documents).__name

Error message

Expected documents to be a list, got {type(documents).__name__}

What it means

validate_documents requires the documents argument to be a Python list of strings. A bare string (the most common mistake), tuple, generator, or None raises this ValueError with the type name reported. With nullable=True, individual None entries are allowed, but the outer value must still be a list.

Source

Thrown at chromadb/api/types.py:1443

        raise ValueError(
            f"Expected sparse vectors to be a list, got {type(vectors).__name__}"
        )
    if len(vectors) == 0:
        raise ValueError(
            f"Expected sparse vectors to be a non-empty list, got {len(vectors)} sparse vectors"
        )
    for i, vector in enumerate(vectors):
        if not isinstance(vector, SparseVector):
            raise ValueError(
                f"Expected SparseVector instance at position {i}, got {type(vector).__name__}"
            )
    return vectors


def validate_documents(documents: Documents, nullable: bool = False) -> None:
    """Validates documents to ensure it is a list of strings"""
    if not isinstance(documents, list):
        raise ValueError(
            f"Expected documents to be a list, got {type(documents).__name__}"
        )
    if len(documents) == 0:
        raise ValueError(
            f"Expected documents to be a non-empty list, got {len(documents)} documents"
        )
    for document in documents:
        # If embeddings are present, some documents can be None
        if document is None and nullable:
            continue
        if not is_document(document):
            raise ValueError(f"Expected document to be a str, got {document}")


def validate_images(images: Images) -> None:
    """Validates images to ensure it is a list of numpy arrays"""
    if not isinstance(images, list):
        raise ValueError(f"Expected images to be a list, got {type(images).__name__}")

View on GitHub (pinned to aecdd12c8a)

Solutions

  1. Wrap single documents in a list: documents=["hello world"]
  2. Normalize defensively: documents = [documents] if isinstance(documents, str) else list(documents)
  3. Match list lengths — ids, documents, and metadatas must all be equal length

Example fix

# before
collection.add(ids=["doc1"], documents="hello world")

# after
collection.add(ids=["doc1"], documents=["hello world"])
Defensive patterns

Strategy: type-guard

Validate before calling

def normalize_documents(docs):
    if isinstance(docs, str):
        docs = [docs]
    elif not isinstance(docs, list):
        docs = list(docs)
    if not docs:
        raise ValueError("documents must be a non-empty list")
    return docs

collection.add(ids=ids, documents=normalize_documents(docs))

Type guard

from typing import Any

def is_document_list(docs: Any) -> bool:
    return isinstance(docs, list) and all(d is None or isinstance(d, str) for d in docs)

Try / catch

try:
    collection.upsert(ids=ids, documents=docs, metadatas=metas)
except ValueError as e:
    if "Expected documents to be a list" in str(e) and isinstance(docs, str):
        collection.upsert(ids=ids, documents=[docs], metadatas=metas)  # self-heal bare string
    else:
        raise

Prevention

When it happens

Trigger: collection.add(ids=["1"], documents="hello world") — one document passed as a bare string instead of ["hello world"]; documents=("a", "b") as a tuple; documents=some_generator.

Common situations: Single-document helpers/upserts where the author forgets the list; treating a long string as already-listed; tuple literals reused from config; iterating a file object directly instead of readlines().

Related errors


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