chroma-core/chroma · error · ValueError

Expected sparse vectors to be a non-empty list, got {len(vec

Error message

Expected sparse vectors to be a non-empty list, got {len(vectors)} sparse vectors

What it means

validate_sparse_vectors rejects an empty list (len == 0). At least one SparseVector must be present, mirroring the dense-embeddings rule; the message echoes the zero count.

Source

Thrown at chromadb/api/types.py:1429

def validate_sparse_vectors(vectors: SparseVectors) -> SparseVectors:
    """Validates sparse vectors to ensure it is a non-empty list of SparseVector instances.

    This function validates the structure and types of sparse vectors returned by
    SparseEmbeddingFunction implementations. It ensures:
    - Vectors is a list
    - List is non-empty
    - All items are SparseVector instances

    Note: Individual SparseVector validation (sorted indices, non-negative values, etc.)
    happens automatically in SparseVector.__post_init__ when each instance is created.
    This function only validates the list structure and instance types.
    """
    if not isinstance(vectors, list):
        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(

View on GitHub (pinned to aecdd12c8a)

Solutions

  1. Skip the call when there is nothing to embed: if not texts: return []
  2. Guard at the call site: if sparse_vectors: collection.add(..., sparse_vectors=sparse_vectors)
  3. Fix upstream filtering that dropped every row in the batch

Example fix

# before
sv = sparse_ef(texts)              # texts == [] -> []
collection.add(ids=ids, sparse_vectors=sv, documents=texts)

# after
if texts:
    sv = sparse_ef(texts)
    collection.add(ids=ids, sparse_vectors=sv, documents=texts)
Defensive patterns

Strategy: validation

Validate before calling

def sparse_add(collection, ids, texts, sparse_ef):
    if not texts:
        return  # nothing to embed — skip instead of calling with []
    sv = sparse_ef(texts)
    if not sv:
        raise ValueError("sparse embedding function returned an empty list for non-empty input")
    collection.add(ids=ids, documents=texts, sparse_vectors=sv)

Type guard

def is_non_empty_sparse_list(v) -> bool:
    return isinstance(v, list) and len(v) > 0

Try / catch

try:
    collection.query(query_texts=[q], sparse_vectors=sv if sv else None)
except ValueError as e:
    if "non-empty list, got 0 sparse vectors" in str(e):
        logger.warning("empty sparse batch skipped")
    else:
        raise

Prevention

When it happens

Trigger: A SparseEmbeddingFunction invoked on an empty input list returning []; calling add()/query() with sparse_vectors=[]; batch loops that don't skip empty batches.

Common situations: Hybrid-search pipelines where chunking or filtering produced zero texts for one batch; per-file processing of empty files; reusing the dense-pipeline guard code that was never written.

Related errors


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