mem0ai/mem0 · error · ValueError

Unsupported metadata filter operator: {operator}

Error message

Unsupported metadata filter operator: {operator}

What it means

Raised inside _process_metadata_filters (used by search()/get_all() when advanced operators are detected) when a condition dict uses an operator key outside the supported set. Supported operators are exactly: eq, ne, gt, gte, lt, lte, in, nin, contains, icontains. Anything else — 'gteq', 'between', 'regex', 'exists', '$gte' with a dollar prefix, or a typo — raises this ValueError naming the bad operator.

Source

Thrown at mem0/memory/main.py:1556

                # Simple equality: {"key": "value"}
                if condition == "*":
                    # Wildcard: match everything for this field (implementation depends on vector store)
                    return {key: "*"}
                return {key: condition}

            result = {}
            for operator, value in condition.items():
                # Map platform operators to universal format that can be translated by each vector store
                operator_map = {
                    "eq": "eq", "ne": "ne", "gt": "gt", "gte": "gte",
                    "lt": "lt", "lte": "lte", "in": "in", "nin": "nin",
                    "contains": "contains", "icontains": "icontains"
                }

                if operator in operator_map:
                    result.setdefault(key, {})[operator_map[operator]] = value
                else:
                    raise ValueError(f"Unsupported metadata filter operator: {operator}")
            return result

        def merge_filters(target: Dict[str, Any], source: Dict[str, Any]) -> None:
            """Merge source into target, deep-merging nested operator dicts for the same key."""
            for key, value in source.items():
                if key in target and isinstance(target[key], dict) and isinstance(value, dict):
                    target[key].update(value)
                else:
                    target[key] = value

        for key, value in metadata_filters.items():
            if key == "AND":
                # Logical AND: combine multiple conditions
                if not isinstance(value, list):
                    raise ValueError("AND operator requires a list of conditions")
                for condition in value:
                    for sub_key, sub_value in condition.items():
                        merge_filters(processed_filters, process_condition(sub_key, sub_value))

View on GitHub (pinned to 001c235229)

Solutions

  1. Replace the operator with one of the ten supported names, lowercase, no $ prefix (e.g. $gte -> gte, $in -> in).
  2. Express 'between' as two conditions merged under AND: {'AND': [{'ts': {'gte': 1}}, {'ts': {'lte': 2}}]}.
  3. Validate filter dicts against the supported set before calling search/get_all (see validation code in the defense section).
  4. For regex-like matching, use contains/icontains for substring and case-insensitive substring respectively.

Example fix

# before
filters = {"user_id": "u1", "score": {"$gte": 0.5}}

# after
filters = {"user_id": "u1", "score": {"gte": 0.5}}
Defensive patterns

Strategy: validation

Validate before calling

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

def validate_filters(filters):
    for key, value in filters.items():
        if key in LOGICAL_OPS:
            if not isinstance(value, list):
                raise ValueError(f"{key} must be a list")
            for cond in value:
                validate_filters(cond)
        elif isinstance(value, dict):
            bad = set(value) - SUPPORTED_OPS
            if bad:
                raise ValueError(f"unsupported operators: {bad}; supported: {sorted(SUPPORTED_OPS)}")

Type guard

def is_supported_operator(op: str) -> bool:
    return op in {"eq", "ne", "gt", "gte", "lt", "lte", "in", "nin", "contains", "icontains"}

Prevention

When it happens

Trigger: filters={'user_id':'u1','score':{'$gte':0.5}} using Mongo-style $-prefixed operators; {'ts':{'between':[1,2]}}; {'name':{'regex':'^a'}}; typo 'gte ' with whitespace or 'GTE' uppercase (matching is case-sensitive); copying filter syntax from Pinecone/Qdrant/Mongo docs into mem0 filters.

Common situations: Developers fluent in MongoDB or Elasticsearch filter syntax assuming the same grammar; LLM-generated filter dicts inventing operators; case mismatches from config-driven filter construction.

Related errors


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