MemPalace/mempalace · error · UnsupportedFilterError
operator {key!r} not supported by milvus
Error message
operator {key!r} not supported by milvus What it means
Raised in _translate_clause() when a where-clause key starts with '$' but is neither '$and' nor '$or'. At the clause level only those two logical operators exist; all $-prefixed field names or misplaced operators ($in, $contains at top level, $nor, etc.) hit this branch and raise UnsupportedFilterError. This guards against typos and against putting field-level operators at the wrong nesting depth.
Source
Thrown at mempalace/backends/milvus.py:162
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))
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")View on GitHub (pinned to 06cb6987f0)
Solutions
- Move operators inside a field dict: {"wing": {"$in": [...]}} not {"$in": [...]}
- Rename metadata keys that start with '$' — _field_name would reject them anyway
- Rewrite $not via $ne/$nin on the field
Example fix
// before
where = {"$in": ["a", "b"]}
// after
where = {"wing": {"$in": ["a", "b"]}} Defensive patterns
Strategy: validation
Validate before calling
CLAUSE_LEVEL_OPS = {"$and", "$or"}
def no_misplaced_operators(where: dict) -> bool:
return all(k in CLAUSE_LEVEL_OPS or not k.startswith("$") for k in where) Try / catch
from mempalace.backends.base import UnsupportedFilterError
try:
collection.query(query_texts=[q], where=where, n_results=k)
except UnsupportedFilterError as e:
if "not supported by milvus" in str(e):
raise ValueError(f"move operator {e} inside a field's condition dict") from e
raise Prevention
- Operators like $in/$contains belong inside a field dict, not at clause level
- Never name metadata fields with a leading '$'
- Lift shared filter-shape checks into unit tests
When it happens
Trigger: where={"$in": [...]}, where={"$not": {...}}, or a metadata field literally named "$price" used as a clause key. Distinct from error 24, which fires for unknown operators nested inside a field's condition dict.
Common situations: Misplaced operators after refactoring filter-building code; Mongo $nor/$not habits; metadata keys that begin with a dollar sign.
Related errors
- operator {op!r} not supported by milvus
- where_document operator {key!r} not supported
- 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}
AI-assisted analysis of MemPalace/mempalace@06cb6987f0 (2026-08-15).
Data as JSON: /api/errors/a41b5ed02c4dccf1.
Report an issue: GitHub.