MemPalace/mempalace · error · UnsupportedFilterError
where clause must be a dict, got {type(clause).__name__}
Error message
where clause must be a dict, got {type(clause).__name__} What it means
Raised by _translate_clause() when the where argument (or a nested $and/$or element) is not a dict — e.g. a list, string, or None inside a nested position. The portable DSL requires every clause level to be a mapping of field→condition or operator→subclauses; anything else fails translation with UnsupportedFilterError before Milvus is contacted. Note the top-level falsy case ({}, None) is fine and yields an empty filter — only non-dict truthy values fail.
Source
Thrown at mempalace/backends/milvus.py:146
elif op == "$gt":
parts.append(f"{field} > {_quote_value(operand)}")
elif op == "$gte":
parts.append(f"{field} >= {_quote_value(operand)}")
elif op == "$lt":
parts.append(f"{field} < {_quote_value(operand)}")
elif op == "$lte":
parts.append(f"{field} <= {_quote_value(operand)}")
elif op == "$contains":
parts.append(f"{field} like {_like_value(operand)}")
else:
raise UnsupportedFilterError(f"operator {op!r} not supported by milvus")
return " and ".join(parts)
return f"{field} == {_quote_value(expected)}"
def _translate_clause(clause: dict) -> str:
if not isinstance(clause, dict):
raise UnsupportedFilterError(f"where clause must be a dict, got {type(clause).__name__}")
if not clause:
return ""
parts = []
for key, value in clause.items():
if key == "$and":
if not isinstance(value, list) or not value:
raise UnsupportedFilterError("$and requires a non-empty list of clauses")
nested = [_translate_clause(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_clause(item) for item in value]
parts.append("(" + " or ".join(part for part in nested if part) + ")")
elif key.startswith("$"):
raise UnsupportedFilterError(f"operator {key!r} not supported by milvus")
else:
parts.append(_translate_field(key, value))View on GitHub (pinned to 06cb6987f0)
Solutions
- Pass a plain dict: where={"wing": "alice"}, not a list or expression string
- For raw Milvus filter expressions, use the backend's native filter escape hatch (if exposed) instead of where
- Validate nested $and/$or elements are all dicts before calling query
Example fix
// before
results = collection.query(query_texts=[q], where=[{"wing": "alice"}])
// after
results = collection.query(query_texts=[q], where={"wing": "alice"}) Defensive patterns
Strategy: type-guard
Validate before calling
def validate_where(where) -> dict:
if not where:
return {}
if not isinstance(where, dict):
raise TypeError(f"where must be a dict, got {type(where).__name__}")
for k, v in where.items():
if k in ("$and", "$or"):
for item in v:
validate_where(item)
return where Type guard
def is_where_dict(where) -> bool:
"""True when every clause node is a dict and $and/$or carry list-of-dict."""
if not isinstance(where, dict):
return False
for k, v in where.items():
if k in ("$and", "$or"):
if not isinstance(v, list) or not v:
return False
if not all(is_where_dict(item) for item in v):
return False
return True Try / catch
from mempalace.backends.base import UnsupportedFilterError
try:
collection.query(query_texts=[q], where=where, n_results=k)
except UnsupportedFilterError as e:
if "must be a dict" in str(e):
raise TypeError("pass where as a dict, not a list or expression string") from e
raise Prevention
- Always author where as a plain dict
- Do not feed raw Milvus expression strings into where
- Validate deserialized JSON filters before querying
When it happens
Trigger: where=[{"wing": "a"}] (list-wrapped clause, Mongo habit), where="wing = 'a'" (raw expression string), or nested={"$or": [{"a": 1}, "b"]} where one $or element is a bare string.
Common situations: Copy-pasting raw Milvus filter expression strings from Milvus docs into the where parameter; JSON-decoded filters where a nested element is not an object; wrappers that accept multiple clause shapes.
Related errors
- where_document must be a dict
- Milvus filters do not support null comparisons
- Milvus filter field {name!r} is not a safe identifier
- $in requires a non-empty list for {field!r}
- $nin requires a non-empty list for {field!r}
AI-assisted analysis of MemPalace/mempalace@06cb6987f0 (2026-08-15).
Data as JSON: /api/errors/cb7a6d9d8e27e7f6.
Report an issue: GitHub.