MemPalace/mempalace · error · UnsupportedFilterError

where_document must be a dict

Error message

where_document must be a dict

What it means

Raised by translate_where_document() when where_document is truthy but not a dict. The document filter only supports a small object shape ($contains, $and, $or), so passing a string, list, or other type fails with UnsupportedFilterError before translation. Falsy values (None, {}, "") are fine and produce an empty filter.

Source

Thrown at mempalace/backends/milvus.py:180

            raise UnsupportedFilterError(f"operator {key!r} not supported by milvus")
        else:
            parts.append(_translate_field(key, value))
    return " and ".join(part for part in parts if part)


def translate_where(where: Optional[dict]) -> str:
    """Translate the portable metadata where DSL into a Milvus filter string."""
    if not where:
        return ""
    return _translate_clause(where)


def translate_where_document(where_document: Optional[dict]) -> str:
    """Translate the portable document filter subset into a Milvus filter."""
    if not where_document:
        return ""
    if not isinstance(where_document, dict):
        raise UnsupportedFilterError("where_document must be a dict")
    parts = []
    for key, value in where_document.items():
        if key == "$contains":
            parts.append(f"{FIELD_DOCUMENT} like {_like_value(value)}")
        elif key == "$and":
            if not isinstance(value, list) or not value:
                raise UnsupportedFilterError("$and requires a non-empty list of clauses")
            nested = [translate_where_document(item) for item in value]
            parts.append("(" + " and ".join(part for part in nested if part) + ")")
        elif key == "$or":
            if not isinstance(value, list) or not value:
                raise UnsupportedFilterError("$or requires a non-empty list of clauses")
            nested = [translate_where_document(item) for item in value]
            parts.append("(" + " or ".join(part for part in nested if part) + ")")
        else:
            raise UnsupportedFilterError(f"where_document operator {key!r} not supported")
    return " and ".join(part for part in parts if part)

View on GitHub (pinned to 06cb6987f0)

Solutions

  1. Always pass the object form: where_document={"$contains": "palace"}
  2. Add a wrapper that converts a bare string s to {"$contains": s}
  3. Validate JSON-decoded where_document payloads with isinstance checks before querying

Example fix

// before
results = collection.query(query_texts=[q], where_document="palace")

// after
results = collection.query(query_texts=[q], where_document={"$contains": "palace"})
Defensive patterns

Strategy: type-guard

Validate before calling

def normalize_where_document(wd):
    if not wd:
        return None
    if isinstance(wd, str):
        return {"$contains": wd}
    if not isinstance(wd, dict):
        raise TypeError(f"where_document must be a dict, got {type(wd).__name__}")
    return wd

Type guard

def is_where_document_dict(wd) -> bool:
    return wd is None or wd == {} or isinstance(wd, dict)

Try / catch

from mempalace.backends.base import UnsupportedFilterError
try:
    collection.query(query_texts=[q], where_document=wd, n_results=k)
except UnsupportedFilterError as e:
    if "where_document must be a dict" in str(e):
        wd = {"$contains": str(wd)}
        return collection.query(query_texts=[q], where_document=wd, n_results=k)
    raise

Prevention

When it happens

Trigger: where_document="$contains palace" (operator string instead of dict), where_document=["palace"], or a JSON-parsed value that is a list at the top level.

Common situations: Copy-pasting the substring directly instead of the {$contains: ...} wrapper; wrappers that accept shorthand strings; porting ChromaDB examples incorrectly.

Related errors


AI-assisted analysis of MemPalace/mempalace@06cb6987f0 (2026-08-15). Data as JSON: /api/errors/693956172f30f7bc. Report an issue: GitHub.