chroma-core/chroma · error · ValueError

Expected dict with {TYPE_KEY}='{SPARSE_VECTOR_TYPE_VALUE}',

Error message

Expected dict with {TYPE_KEY}='{SPARSE_VECTOR_TYPE_VALUE}', got {query}

What it means

When $knn's 'query' is a dict, the parser expects the SparseVector transport format, which is tagged with a discriminator: {'#type': 'sparse_vector', 'indices': [...], 'values': [...], 'tokens': [...]} (TYPE_KEY='#type', SPARSE_VECTOR_TYPE_VALUE='sparse_vector', chromadb/base_types.py:8-9). A dict without that exact marker - old formats or hand-built {'indices', 'values'} dicts - is rejected with this ValueError.

Source

Thrown at chromadb/execution/expression/operator.py:705

            return Val(value)

        elif op == "$knn":
            knn_data = data["$knn"]
            if not isinstance(knn_data, dict):
                raise TypeError(f"$knn requires a dict, got {type(knn_data).__name__}")

            if "query" not in knn_data:
                raise ValueError("$knn requires 'query' field")

            query = knn_data["query"]

            if isinstance(query, dict):
                # SparseVector case - deserialize from transport format
                if query.get(TYPE_KEY) == SPARSE_VECTOR_TYPE_VALUE:
                    query = SparseVector.from_dict(query)
                else:
                    # Old format or invalid - try to construct directly
                    raise ValueError(
                        f"Expected dict with {TYPE_KEY}='{SPARSE_VECTOR_TYPE_VALUE}', got {query}"
                    )

            elif isinstance(query, (list, tuple, np.ndarray)):
                # Dense vector case - normalize then validate
                normalized = normalize_embeddings(query)
                if not normalized or len(normalized) > 1:
                    raise ValueError("$knn requires exactly one query embedding")

                # Validate the normalized version
                validate_embeddings(normalized)

                query = normalized[0]

            else:
                raise TypeError(
                    f"$knn query must be a list, numpy array, or SparseVector dict, got {type(query).__name__}"
                )

View on GitHub (pinned to aecdd12c8a)

Solutions

  1. Add the tag: {'#type': 'sparse_vector', **sparse_dict}.
  2. Build the payload with SparseVector(indices=..., values=...).to_dict() so the tag is always correct.
  3. For dense queries, pass a list/array instead of a dict.

Example fix

# before
query = {'indices': [0, 2], 'values': [0.1, 0.3]}
Search(rank={'$knn': {'query': query}})    # -> ValueError

# after
from chromadb.base_types import SparseVector
query = SparseVector(indices=[0, 2], values=[0.1, 0.3]).to_dict()
Search(rank={'$knn': {'query': query}})
Defensive patterns

Strategy: validation

Validate before calling

from chromadb.base_types import SparseVector

def sparse_query(indices, values, labels=None):
    return SparseVector(indices=indices, values=values, labels=labels).to_dict()

Search(rank={'$knn': {'query': sparse_query([0, 2], [0.1, 0.3])}})

Type guard

from chromadb.base_types import TYPE_KEY, SPARSE_VECTOR_TYPE_VALUE

def is_sparse_vector_dict(d) -> bool:
    return isinstance(d, dict) and d.get(TYPE_KEY) == SPARSE_VECTOR_TYPE_VALUE

Prevention

When it happens

Trigger: Search(rank={'$knn': {'query': {'indices': [0, 2], 'values': [0.1, 0.3]}}}) with no #type key; embedding dicts persisted before the type tag existed; sparse queries assembled by hand from tokenizer output.

Common situations: Storing SparseVector fields in your own DB as {indices, values} and feeding them back into $knn; upgrading Chroma versions where older payloads lack the discriminator; using 'type' instead of '#type' as the key.

Related errors


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