mem0ai/mem0 · error · ValueError

Unsupported filter operator(s) for field '{key}': {ops}. Sup

Error message

Unsupported filter operator(s) for field '{key}': {ops}. Supported operators: {supported}

What it means

Raised by Qdrant's `_build_field_condition` when a field dict's keys are none of the ten supported operators (eq, ne, gt, gte, lt, lte, in, nin, contains, icontains). It is the catch-all for misspelled or unrecognized operators, and the message enumerates the full supported set so the fix is mechanical.

Source

Thrown at mem0/vector_stores/qdrant.py:334

            return FieldCondition(key=key, match=MatchAny(any=value["in"]))
        elif "nin" in value:
            return FieldCondition(key=key, match=MatchExcept(**{"except": value["nin"]}))
        elif "contains" in value or "icontains" in value:
            # MatchText: with a full-text index, tokenized matching (all words must appear).
            # Without a full-text index, exact substring match.
            op = "icontains" if "icontains" in value else "contains"
            text = value[op]
            if op == "icontains":
                logger.debug(
                    "icontains on field '%s': Qdrant MatchText case sensitivity depends on "
                    "full-text index configuration. Without a full-text index this behaves "
                    "as a case-sensitive substring match (same as 'contains').",
                    key,
                )
            return FieldCondition(key=key, match=MatchText(text=text))
        else:
            supported = {"eq", "ne", "gt", "gte", "lt", "lte", "in", "nin", "contains", "icontains"}
            raise ValueError(
                f"Unsupported filter operator(s) for field '{key}': {ops}. "
                f"Supported operators: {supported}"
            )

    def _create_filter(self, filters: dict) -> Optional[Filter]:
        """
        Create a Filter object from the provided filters.

        Supports the enhanced filter syntax with comparison operators (eq, ne,
        gt, gte, lt, lte), list operators (in, nin), string operators (contains,
        icontains), and logical operators (AND, OR, NOT).

        Args:
            filters (dict): Filters to apply.

        Returns:
            Filter: The created Filter object, or None if filters is empty.
        """

View on GitHub (pinned to 001c235229)

Solutions

  1. Rewrite the operator using the supported set: `equals`→`eq`, `$gt`→`gt`, `between`→ two AND clauses with gte/lte.
  2. For prefix/substring needs, use `contains`/`icontains` (MatchText) — anything beyond that must be applied client-side after retrieval.
  3. If an empty operator dict slipped in from optional user input, strip falsy entries before passing filters.

Example fix

# before
filters = {"status": {"equals": "active"}}

# after
filters = {"status": {"eq": "active"}}

# between -> two range conditions
# before: {"score": {"between": [1, 5]}}
filters = {"AND": [{"score": {"gte": 1}}, {"score": {"lte": 5}}]}
Defensive patterns

Strategy: type-guard

Validate before calling

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

def check_filters(filters: dict) -> None:
    for key, value in filters.items():
        if isinstance(value, dict):
            bad = set(value) - SUPPORTED_OPS
            if bad or not value:
                raise ValueError(f"Bad filter for {key}: unsupported/empty ops {bad or '{}'}")

Type guard

def is_supported_condition(cond) -> bool:
    if not isinstance(cond, dict) or not cond:
        return False
    return set(cond) <= {"eq", "ne", "gt", "gte", "lt", "lte", "in", "nin", "contains", "icontains"}

Try / catch

try:
    results = memory.search("q", filters=filters)
except ValueError as e:
    if "Unsupported filter operator" in str(e):
        raise BadRequest(f"Rejected filter syntax: {filters}") from e
    raise

Prevention

When it happens

Trigger: Filters containing `{"field": {"between": [1, 5]}}`, `{"field": {"equals": "x"}}`, `{"field": {"$eq": "x"}}` (Mongo-style $ prefixes), `{"field": {"starts_with": "abc"}}`, or an empty dict `{"field": {}}` which falls through every elif.

Common situations: Translating MongoDB/SQL WHERE clauses to mem0 filter syntax; LLM-generated filters inventing plausible operator names; typos like 'gte ' with whitespace or 'GTE' capitalized; assuming regex/prefix operators exist because the docs mention full-text search.

Related errors


AI-assisted analysis of mem0ai/mem0@001c235229 (2026-08-15). Data as JSON: /api/errors/22d7e19599648f83. Report an issue: GitHub.