MemPalace/mempalace · error · UnsupportedFilterError

operator {op!r} not supported by milvus

Error message

operator {op!r} not supported by milvus

What it means

Raised in _translate_field() when a field's operator dict contains a key other than the supported set ($eq, $ne, $in, $nin, $gt, $gte, $lt, $lte, $contains). The Milvus backend only implements this portable subset of the metadata DSL; unknown operators are rejected with UnsupportedFilterError during translation so no invalid filter string reaches the server.

Source

Thrown at mempalace/backends/milvus.py:139

                items = ", ".join(_quote_value(item) for item in operand)
                parts.append(f"{field} in [{items}]")
            elif op == "$nin":
                if not isinstance(operand, list) or not operand:
                    raise UnsupportedFilterError(f"$nin requires a non-empty list for {field!r}")
                items = ", ".join(_quote_value(item) for item in operand)
                parts.append(f"{field} not in [{items}]")
            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:

View on GitHub (pinned to 06cb6987f0)

Solutions

  1. Replace $regex with $contains (translated to Milvus 'like') where substring semantics suffice
  2. Replace $exists/$type checks by filtering on a stored sentinel value instead
  3. Express ranges with $gte/$lt combinations
  4. Run per-backend capability checks before building the clause

Example fix

// before
where = {"note": {"$regex": "palace"}}

// after
where = {"note": {"$contains": "palace"}}
Defensive patterns

Strategy: validation

Validate before calling

SUPPORTED_OPS = {"$eq", "$ne", "$in", "$nin", "$gt", "$gte", "$lt", "$lte", "$contains"}

def uses_supported_operators(where: dict) -> bool:
    for v in where.values():
        if isinstance(v, dict):
            for op in v:
                if op not in SUPPORTED_OPS:
                    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:
    raise ValueError(f"rewrite filter for milvus backend: {e}") from e

Prevention

When it happens

Trigger: where={"age": {"$exists": True}}, {"name": {"$regex": "^a"}}, {"ts": {"$between": [1, 2]}}, or any Mongo-style operator ($and/$or excluded — those are handled at clause level) unsupported here.

Common situations: Porting MongoDB or ChromaDB where-clauses that use richer operators; sharing filter builders across backends without trimming to the supported subset.

Related errors


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