mem0ai/mem0 · error · ValueError

Invalid datetime value in range filter for field '{key}': {e

Error message

Invalid datetime value in range filter for field '{key}': {e}

What it means

Raised when Qdrant's filter builder detects a datetime-shaped range (values that look like dates/timestamps) but the upstream DatetimeRange constructor rejects the values — typically strings that are not valid RFC 3339 / ISO 8601 timestamps or non-numeric types. The original ValueError/TypeError from Qdrant is chained (`from e`) so the underlying parse failure is preserved in the message.

Source

Thrown at mem0/vector_stores/qdrant.py:307

            return FieldCondition(key=key, match=MatchValue(value=value))

        ops = set(value.keys())
        range_ops = {"gt", "gte", "lt", "lte"}
        non_range_ops = ops - range_ops

        if ops & range_ops:
            if non_range_ops:
                raise ValueError(
                    f"Cannot mix range operators ({ops & range_ops}) with "
                    f"non-range operators ({non_range_ops}) for field '{key}'. "
                    f"Use AND to combine them as separate conditions."
                )
            range_kwargs = {op: value[op] for op in range_ops if op in value}
            if self._is_datetime_range(range_kwargs):
                try:
                    return FieldCondition(key=key, range=DatetimeRange(**range_kwargs))
                except (ValueError, TypeError) as e:
                    raise ValueError(
                        f"Invalid datetime value in range filter for field '{key}': {e}"
                    ) from e
            return FieldCondition(key=key, range=Range(**range_kwargs))
        elif "eq" in value:
            return FieldCondition(key=key, match=MatchValue(value=value["eq"]))
        elif "ne" in value:
            return FieldCondition(key=key, match=MatchExcept(**{"except": [value["ne"]]}))
        elif "in" in value:
            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(

View on GitHub (pinned to 001c235229)

Solutions

  1. Normalize date inputs to ISO 8601 / RFC 3339 before filtering: `datetime.isoformat()` or `dateutil.parser.parse(raw).isoformat()`.
  2. If the field is actually numeric (unix epoch), pass ints/floats so `_is_datetime_range` routes it to the plain Range constructor instead of DatetimeRange.
  3. Upgrade qdrant-client — DatetimeRange parsing strictness has changed between versions; align client and server versions.

Example fix

# before
filters = {"created_at": {"gte": "01/02/2024"}}

# after
from datetime import datetime, timezone
from dateutil import parser

def to_iso(raw: str) -> str:
    return parser.parse(raw).astimezone(timezone.utc).isoformat()

filters = {"created_at": {"gte": to_iso("2024-01-02")}}
Defensive patterns

Strategy: validation

Validate before calling

from datetime import datetime

def iso_or_none(raw) -> str | None:
    if raw is None:
        return None
    dt = datetime.fromisoformat(str(raw).replace("Z", "+00:00"))  # raises on garbage
    return dt.isoformat()

filters = {"created_at": {"gte": iso_or_none(user_input)}}

Type guard

def is_parseable_datetime(v) -> bool:
    if isinstance(v, (int, float)) and not isinstance(v, bool):
        return True  # epoch values go to plain Range
    if not isinstance(v, str):
        return False
    try:
        datetime.fromisoformat(v.replace("Z", "+00:00"))
        return True
    except ValueError:
        return False

Try / catch

try:
    results = memory.search("q", filters=filters)
except ValueError as e:
    if "Invalid datetime value" in str(e):
        raise ValueError(f"Bad date filter from caller: {filters}; expected ISO 8601") from e
    raise

Prevention

When it happens

Trigger: Filters such as `{"created_at": {"gte": "yesterday"}}`, `{"created_at": {"lt": "2024-13-45"}}`, `{"created_at": {"gte": "01/02/2024"}}` (slash format), or passing None/bool where a timestamp is expected — any value DatetimeRange cannot parse.

Common situations: Free-form user input used directly as a date filter; locale-specific date formats (MM/DD/YYYY vs ISO); LLM tool-calls emitting relative dates like 'last week' instead of ISO strings; storing timestamps with a 'Z' suffix or offset that the installed qdrant-client version rejects.

Related errors


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