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

  1. Use dict syntax with exactly one top-level key: where={"source": "wiki"}.
  2. Combine multiple conditions under $and/$or: where={"$and": [{"a": 1}, {"b": 2}]} instead of a list or a multi-key dict.
  3. Omit the where kwarg entirely (or pass None) when no filter is needed rather than an empty string/list.
  4. 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

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


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