chroma-core/chroma · error · ValueError
Expected where to be a dict, got {where}
Error message
Expected where to be a dict, got {where} What it means
ChromaDB's `where` filter must be a dict with exactly one top-level entry (a field name, `$and`, `$or`, `$in`, or `$nin`). `validate_where` rejects anything that is not a dict — lists of conditions, strings, or None — with this ValueError. The check runs client-side on every query/get/count/delete that passes a `where`, and is re-run server-side by the Rust/Segment API.
Source
Thrown at chromadb/api/types.py:1192
return result
def validate_metadatas(metadatas: Metadatas) -> Metadatas:
"""Validates metadatas to ensure it is a list of dictionaries of strings to strings, ints, floats or bools"""
if not isinstance(metadatas, list):
raise ValueError(f"Expected metadatas to be a list, got {metadatas}")
for metadata in metadatas:
validate_metadata(metadata)
return metadatas
def validate_where(where: Where) -> None:
"""
Validates where to ensure it is a dictionary of strings to strings, ints, floats or operator expressions,
or in the case of $and and $or, a list of where expressions
"""
if not isinstance(where, dict):
raise ValueError(f"Expected where to be a dict, got {where}")
if len(where) != 1:
raise ValueError(f"Expected where to have exactly one operator, got {where}")
for key, value in where.items():
if not isinstance(key, str):
raise ValueError(f"Expected where key to be a str, got {key}")
# $contains and $not_contains are only valid as operators within a
# field expression (e.g. {"field": {"$contains": val}}), not as
# top-level where keys.
if key in ("$contains", "$not_contains"):
raise ValueError(
f"Expected where key to be a metadata field name or a logical "
f"operator ($and, $or), got {key}"
)
if (
key != "$and"
and key != "$or"
and key != "$in"
and key != "$nin"View on GitHub (pinned to aecdd12c8a)
Solutions
- Use dict syntax with exactly one top-level key: where={"source": "wiki"}.
- Combine multiple conditions under $and/$or: where={"$and": [{"a": 1}, {"b": 2}]} instead of a list or a multi-key dict.
- Omit the where kwarg entirely (or pass None) when no filter is needed rather than an empty string/list.
- If building filters dynamically, assert isinstance(where, dict) before calling the API.
Example fix
# before
collection.query(query_embeddings=[q], where=[{"source": "wiki"}, {"year": 2024}])
# after
collection.query(query_embeddings=[q], where={"$and": [{"source": "wiki"}, {"year": 2024}]}) Defensive patterns
Strategy: type-guard
Validate before calling
def is_valid_where(where):
return where is None or isinstance(where, dict) Type guard
from typing import TypeGuard
from chromadb.api.types import Where
def is_where(value: object) -> TypeGuard[Where]:
return isinstance(value, dict) and len(value) == 1 and all(isinstance(k, str) for k in value) Try / catch
try:
collection.query(query_embeddings=[q], where=where)
except ValueError as e:
if "Expected where to be a dict" in str(e):
raise ValueError(f"Invalid where filter {where!r}: must be a single-key dict") from e
raise Prevention
- Treat filters as data built by one helper function, never assembled ad hoc at call sites.
- Omit the where kwarg when unfiltered instead of passing empty strings/lists.
- Before calling the API, assert isinstance(where, dict) and len(where) == 1.
- Call chromadb.api.types.validate_where in unit tests for every filter your app can generate.
When it happens
Trigger: Passing where=[{"a": 1}, {"b": 2}] (list of filters), where="a = 1" (SQL-ish string), where=None explicitly instead of omitting the kwarg, or where built from an empty/uninitialized variable. Common with collection.query(where=...) and collection.get(where=...).
Common situations: Developers coming from SQL or Mongo who build filter strings or condition arrays; passing an optional filter that defaulted to a non-dict sentinel; double-encoding `where` as a JSON string before a REST call; or confusing the one-key rule with multi-key dicts (which raise a different error).
Related errors
- Expected where to have exactly one operator, got {where}
- Expected where to be a non-empty object
- Expected 'where' to have exactly one operator, but got ${Obj
- Exactly one of {', '.join(contains_one)} must be provided
- At least one of ${recordSetFields.join(", ")} must be provid
AI-assisted analysis of chroma-core/chroma@aecdd12c8a (2026-08-16).
Data as JSON: /api/errors/7ef98c2e58f86118.
Report an issue: GitHub.