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
- Rename metadata fields at write time to snake_case identifiers: `user_id` not `user-id`.
- Sanitize or reject keys before calling the API with a mirror of the same regex.
- 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
- Constrain metadata field names to snake_case identifiers at write time — it is the only safe shape for Upstash.
- Map external/dotted keys to flattened underscore names in one normalization function.
- Treat filter-key validation as a security control, not a convenience: reject, don't escape.
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
- Filter value for {key!r} contains prohibited characters (dou
- Filter value for {key!r} must be str, int, float, or bool, g
- AND filter value must be a list of filter dicts, got ${typeo
- OR filter value must be a list of filter dicts, got ${typeof
- NOT 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/98b4a028aed78f00.
Report an issue: GitHub.