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
- Rewrite the operator using the supported set: `equals`→`eq`, `$gt`→`gt`, `between`→ two AND clauses with gte/lte.
- For prefix/substring needs, use `contains`/`icontains` (MatchText) — anything beyond that must be applied client-side after retrieval.
- 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
- Keep a mapping table from your query DSL / Mongo operators to the ten supported ops and translate in one place.
- Treat filters as an API contract: validate them with Pydantic before they reach mem0.
- Cover filter translation with unit tests, including negative cases ($-prefixed ops, empty dicts).
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
- Cannot mix range operators ({ops & range_ops}) with non-rang
- {key} filter value must be a list of filter dicts, got {type
- {key} filter list item at index {i} must be a dict, got {typ
- Invalid datetime value in range filter for field '{key}': {e
- AND filter value must be a list of filter dicts, got ${typeo
AI-assisted analysis of mem0ai/mem0@001c235229 (2026-08-15).
Data as JSON: /api/errors/22d7e19599648f83.
Report an issue: GitHub.