chroma-core/chroma · error · TypeError
$knn query must be a list, numpy array, or SparseVector dict
Error message
$knn query must be a list, numpy array, or SparseVector dict, got {type(query).__name__} What it means
$knn's 'query' must be either a dense vector (list/tuple/np.ndarray) or a serialized SparseVector dict. Anything else - string, int, None - raises TypeError. $knn does not embed raw text; the caller must supply the embedding itself.
Source
Thrown at chromadb/execution/expression/operator.py:721
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__}"
)
key = knn_data.get("key", "#embedding")
if not isinstance(key, str):
raise TypeError(f"$knn key must be a string, got {type(key).__name__}")
limit = knn_data.get("limit", 16)
if not isinstance(limit, int):
raise TypeError(
f"$knn limit must be an integer, got {type(limit).__name__}"
)
if limit <= 0:
raise ValueError(f"$knn limit must be positive, got {limit}")
return_rank = knn_data.get("return_rank", False)
if not isinstance(return_rank, bool):
raise TypeError(View on GitHub (pinned to aecdd12c8a)
Solutions
- Embed first, then query: {'$knn': {'query': embedding_function([text])[0]}}.
- Unwrap extra dict layers so the sequence itself is the query.
- If the embedding is None/unavailable, do not issue the ranked query.
Example fix
# before
Search(rank={'$knn': {'query': 'hello world'}}) # -> TypeError: got str
# after
emb = embedding_function(['hello world'])[0]
Search(rank={'$knn': {'query': emb}}) Defensive patterns
Strategy: type-guard
Validate before calling
def is_queryable_embedding(q) -> bool:
return isinstance(q, (list, tuple)) or isinstance(q, np.ndarray)
if not is_queryable_embedding(q):
q = embedding_function([q])[0] # embed raw text before searching
Search(rank={'$knn': {'query': q}}) Type guard
def is_knn_query(q) -> bool:
if isinstance(q, (list, tuple, np.ndarray)):
return True # dense
return isinstance(q, dict) and q.get('#type') == 'sparse_vector' # sparse Prevention
- $knn never embeds strings - run your embedding function first.
- Assert the query variable is a vector (or tagged sparse dict) before building the payload.
- Fail loudly when the embedding service returns None instead of forwarding it.
When it happens
Trigger: {'$knn': {'query': 'hello world'}} (raw text); {'query': 42}; {'query': None} after a failed embedding call; {'query': {'vector': [...]}} with the list wrapped in an extra dict.
Common situations: Assuming $knn embeds text server-side; optional embeddings defaulting to None; double-wrapping vectors in dicts when adapting another API's payload shape.
Related errors
- $knn requires a dict, got {type(knn_data).__name__}
- $knn requires exactly one query embedding
- $knn key must be a string, got {type(key).__name__}
- $knn limit must be an integer, got {type(limit).__name__}
- $knn return_rank must be a boolean, got {type(return_rank)._
AI-assisted analysis of chroma-core/chroma@aecdd12c8a (2026-08-16).
Data as JSON: /api/errors/204a93aff496b61d.
Report an issue: GitHub.