chroma-core/chroma · error · ValueError

Expected where document operand value for operator {operator

Error message

Expected where document operand value for operator {operator} to be a str, got {operand}

What it means

In validate_where_document, when the operator is one of $contains, $not_contains, $regex, $not_regex (i.e. not a logical operator), the operand must be a Python str. Passing any non-string (int, list, dict, None) raises this ValueError before the query executes.

Source

Thrown at chromadb/api/types.py:1326

            "$or",
        ]:
            raise ValueError(
                f"Expected where document operator to be one of $contains, $not_contains, $regex, $not_regex, $and, $or, got {operator}"
            )
        if operator == "$and" or operator == "$or":
            if not isinstance(operand, list):
                raise ValueError(
                    f"Expected document value for $and or $or to be a list of where document expressions, got {operand}"
                )
            if len(operand) <= 1:
                raise ValueError(
                    f"Expected document value for $and or $or to be a list with at least two where document expressions, got {operand}"
                )
            for where_document_expression in operand:
                validate_where_document(where_document_expression)
        # Value is $contains/$not_contains/$regex/$not_regex operator
        elif not isinstance(operand, str):
            raise ValueError(
                f"Expected where document operand value for operator {operator} to be a str, got {operand}"
            )
        elif len(operand) == 0:
            raise ValueError(
                f"Expected where document operand value for operator {operator} to be a non-empty str"
            )


def validate_include(include: Include, dissalowed: Optional[Include] = None) -> None:
    """Validates include to ensure it is a list of strings. Since get does not allow distances, allow_distances is used
    to control if distances is allowed"""

    if not isinstance(include, list):
        raise ValueError(f"Expected include to be a list, got {include}")
    for item in include:
        if not isinstance(item, str):
            raise ValueError(f"Expected include item to be a str, got {item}")

View on GitHub (pinned to aecdd12c8a)

Solutions

  1. Pass a plain string operand: where_document={"$contains": "hello"}
  2. For multiple alternatives use {"$or": [{"$contains": "a"}, {"$contains": "b"}]}
  3. Cast/validate the value before the call: operand = str(operand) if operand is not None else skip the filter

Example fix

# before
where_document = {"$contains": ["hello", "world"]}

# after
where_document = {"$or": [
    {"$contains": "hello"},
    {"$contains": "world"},
]}
Defensive patterns

Strategy: type-guard

Validate before calling

def normalize_where_document(wd: dict) -> dict:
    out = {}
    for op, operand in wd.items():
        if op in ("$contains", "$not_contains", "$regex", "$not_regex"):
            if not isinstance(operand, str):
                raise TypeError(f"{op} needs a str operand, got {type(operand).__name__}")
            out[op] = operand
        else:
            out[op] = operand
    return out

res = collection.get(where_document=normalize_where_document(wd))

Type guard

STRING_OPS = {"$contains", "$not_contains", "$regex", "$not_regex"}

def is_valid_where_document(wd: object) -> bool:
    if not isinstance(wd, dict) or len(wd) != 1:
        return False
    op, operand = next(iter(wd.items()))
    if op in STRING_OPS:
        return isinstance(operand, str) and len(operand) > 0
    if op in ("$and", "$or"):
        return isinstance(operand, list) and len(operand) >= 2 and all(is_valid_where_document(e) for e in operand)
    return False

Try / catch

try:
    res = collection.get(where_document=wd)
except ValueError as e:
    if "to be a str, got" in str(e):
        raise ValueError(f"bad where_document operand: {wd!r}") from e
    raise

Prevention

When it happens

Trigger: collection.query(query_embeddings=..., where_document={"$contains": 123}) or {"$not_contains": ["a", "b"]} or {"$regex": None}. Also happens when a variable used as the operand is unexpectedly None or a list, e.g. an unrolled parameter from an API request.

Common situations: Passing a list expecting OR-semantics (Chroma needs $or with multiple $contains clauses); a template/config value that arrived as JSON number or null; forgetting that $regex takes the pattern string itself, not a compiled pattern or a (pattern, flags) tuple.

Related errors


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