mem0ai/mem0 · error · ValueError
Invalid query: must be a non-empty string.
Error message
Invalid query: must be a non-empty string.
What it means
Raised by _validate_and_trim_search_query when the 'query' argument to Memory.search() is not a Python str at all (None, int, dict, list, bytes). The message text says 'non-empty string' but this specific branch fires for wrong types; the query must be a string because it is embedded and sent to the vector store as text. This is a fail-fast ValueError before any embedding cost.
Source
Thrown at mem0/memory/main.py:247
)
if top_k is not None:
if not isinstance(top_k, int) or isinstance(top_k, bool):
raise ValueError("top_k must be a valid integer")
if top_k < 0:
raise ValueError(
f"Invalid top_k: {top_k}. Must be a non-negative integer."
)
def _validate_and_trim_search_query(query: str) -> str:
"""
Validates and normalizes a search query before embedding/vector search.
Raises:
ValueError: If query is not a string or is empty/whitespace-only.
"""
if not isinstance(query, str):
raise ValueError("Invalid query: must be a non-empty string.")
trimmed = query.strip()
if not trimmed:
raise ValueError("Invalid query: cannot be empty or whitespace-only.")
return trimmed
def _is_sensitive_field(field_name: str) -> bool:
"""Check if a field should be redacted for telemetry safety.
Uses a layered approach:
1. Runtime fields (allowlist) — always preserved, highest priority.
2. Exact deny list — known secret field names.
3. Suffix deny list — catches patterns like db_password, auth_secret, etc.
"""
name = field_name.lower().strip()
if name in _RUNTIME_FIELDS:
return False
if name in _SENSITIVE_FIELDS_EXACT:View on GitHub (pinned to 001c235229)
Solutions
- Guard with 'if not query: return []' (or raise your own domain error) before calling search().
- Extract the actual string: m.search(payload['question'], ...) instead of m.search(payload, ...).
- Coerce explicitly with str(query) only when you know the value is stringable text.
- Default the parameter to a sensible sentinel and skip the search call when unset.
Example fix
# before
result = m.search(user_question, filters=f) # user_question may be None
# after
if not isinstance(user_question, str) or not user_question.strip():
return []
result = m.search(user_question, filters=f) Defensive patterns
Strategy: type-guard
Validate before calling
if not isinstance(query, str):
raise TypeError(f"query must be str, got {type(query).__name__}") Type guard
def is_searchable_query(q) -> bool:
return isinstance(q, str) and len(q.strip()) > 0 Prevention
- Treat query as a required parameter in your own wrapper signature (no default).
- Check 'if not isinstance(q, str): return []' at the API edge (chat handler, tool entry).
- Decode bytes payloads explicitly; never forward raw network objects.
When it happens
Trigger: m.search(None, filters={'user_id':'u1'}); m.search(12345, ...); m.search({'question': '...'}, ...) passing a dict instead of its content; a variable that is None because an upstream LLM/tool call returned nothing; bytes from a network payload not decoded.
Common situations: Optional query parameters in a wrapper function defaulting to None and being forwarded anyway; template rendering returning None on failure; dataclass/JSON fields assumed to be strings but sometimes null.
Related errors
- top_k must be a valid integer
- Invalid query: cannot be empty or whitespace-only.
- threshold must be a valid number
- Invalid threshold: ${threshold}. Must be between 0 and 1 (in
- topK must be a valid integer
AI-assisted analysis of mem0ai/mem0@001c235229 (2026-08-15).
Data as JSON: /api/errors/4787927997e39cc8.
Report an issue: GitHub.