mem0ai/mem0 · error · ValueError

Invalid filter key: {key!r}

Error message

Invalid filter key: {key!r}

What it means

Raised by the module-level `_validate_filter` helper when a metadata filter key is not a string or does not match the identifier regex `[a-zA-Z_][a-zA-Z0-9_]*`. Upstash Vector filters are serialized into a string query, so unsanitized keys are an injection surface — this strict allowlist blocks quotes, operators, whitespace, dots, hyphens, and unicode before they reach the API.

Source

Thrown at mem0/vector_stores/upstash_vector.py:22

from pydantic import BaseModel

from mem0.vector_stores.base import VectorStoreBase

try:
    from upstash_vector import Index
except ImportError:
    raise ImportError("The 'upstash_vector' library is required. Please install it using 'pip install upstash_vector'.")


logger = logging.getLogger(__name__)

_SAFE_FILTER_KEY = re.compile(r"[a-zA-Z_][a-zA-Z0-9_]*\Z")


def _validate_filter(key: str, value: Any) -> None:
    if not isinstance(key, str) or not _SAFE_FILTER_KEY.fullmatch(key):
        raise ValueError(f"Invalid filter key: {key!r}")
    if not isinstance(value, (str, int, float, bool)):
        raise ValueError(
            f"Filter value for {key!r} must be str, int, float, or bool, "
            f"got {type(value).__name__}"
        )
    if isinstance(value, str) and ('"' in value or "\\" in value):
        raise ValueError(
            f"Filter value for {key!r} contains prohibited characters "
            f"(double quote or backslash): {value!r}"
        )


class OutputData(BaseModel):
    id: Optional[str]  # memory id
    score: Optional[float]  # is None for `get` method
    payload: Optional[Dict]  # metadata

View on GitHub (pinned to 001c235229)

Solutions

  1. Rename metadata fields at write time to snake_case identifiers: `user_id` not `user-id`.
  2. Sanitize or reject keys before calling the API with a mirror of the same regex.
  3. For dotted paths, flatten to a single underscore-joined key when writing payloads, since Upstash metadata is flat.

Example fix

# before
results = memory.search("q", filters={"user-id": "u1", "data.score": 5})

# after
results = memory.search("q", filters={"user_id": "u1", "data_score": 5})
Defensive patterns

Strategy: validation

Validate before calling

import re

SAFE_KEY = re.compile(r"[a-zA-Z_][a-zA-Z0-9_]*\Z")

def sanitize_filter_keys(filters: dict) -> dict:
    bad = [k for k in filters if not isinstance(k, str) or not SAFE_KEY.fullmatch(k)]
    if bad:
        raise ValueError(f"Unsafe/non-identifier filter keys: {bad!r}")
    return filters

Type guard

import re

def is_safe_filter_key(key) -> bool:
    return isinstance(key, str) and re.fullmatch(r"[a-zA-Z_][a-zA-Z0-9_]*", key) is not None

Try / catch

try:
    results = memory.search("q", filters=filters)
except ValueError as e:
    if "Invalid filter key" in str(e):
        raise BadRequest(f"Filter keys must be snake_case identifiers: {filters}") from e
    raise

Prevention

When it happens

Trigger: Insert/search filters with keys like `"user-id"`, `"data.created_at"`, `"1st_flag"`, `"memory type"`, or a non-string key (int from JSON with int keys); any key containing quotes or backslashes.

Common situations: Using arbitrary metadata field names straight from user input or external systems; carrying over field naming conventions (kebab-case, dotted paths) from other schemas; filters generated by an LLM that quotes or decorates key names.

Related errors


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