mem0ai/mem0 · error · Mem0ValidationError
VALIDATION_003
VALIDATION_003
Error message
messages must be str, dict, or list[dict]
What it means
Raised as Mem0ValidationError (VALIDATION_003) by Memory.add() when the messages argument is not a str, dict, or list. The SDK is flexible — a bare string is wrapped as [{'role':'user','content': ...}] and a single dict is wrapped in a list — but tuples of dicts, generators, a JSON string containing a list, pandas rows, or None all fail this check. The details payload records the provided Python type name so you can see exactly what arrived.
Source
Thrown at mem0/memory/main.py:846
if normalized_expiration_date is not None:
processed_metadata["expiration_date"] = normalized_expiration_date
if memory_type is not None and memory_type != MemoryType.PROCEDURAL.value:
raise Mem0ValidationError(
message=f"Invalid 'memory_type'. Please pass {MemoryType.PROCEDURAL.value} to create procedural memories.",
error_code="VALIDATION_002",
details={"provided_type": memory_type, "valid_type": MemoryType.PROCEDURAL.value},
suggestion=f"Use '{MemoryType.PROCEDURAL.value}' to create procedural memories."
)
if isinstance(messages, str):
messages = [{"role": "user", "content": messages}]
elif isinstance(messages, dict):
messages = [messages]
elif not isinstance(messages, list):
raise Mem0ValidationError(
message="messages must be str, dict, or list[dict]",
error_code="VALIDATION_003",
details={"provided_type": type(messages).__name__, "valid_types": ["str", "dict", "list[dict]"]},
suggestion="Convert your input to a string, dictionary, or list of dictionaries."
)
if agent_id is not None and memory_type == MemoryType.PROCEDURAL.value:
results = self._create_procedural_memory(messages, metadata=processed_metadata, prompt=prompt)
scale_threshold_notice = detect_scale_threshold_from_add_result(self, results)
if temporal_usage_notice:
display_temporal_usage_notice(self, "sync", "add", *temporal_usage_notice)
elif scale_threshold_notice:
display_scale_threshold_notice(self, "sync", "add", *scale_threshold_notice)
else:
display_first_run_notice(self, "sync", "add")
return results
if self.config.llm.config.get("enable_vision"):View on GitHub (pinned to 001c235229)
Solutions
- Convert to list: messages = list(messages) before add().
- Pass the Python list of dicts directly, not its JSON serialization.
- Normalize with the documented coercion: str -> auto-wrapped, dict -> [dict], list[dict] -> used as-is.
- Add a type guard in your wrapper: if not isinstance(messages, (str, dict, list)): raise your own error.
Example fix
# before
m.add(({"role": "user", "content": "hi"},), user_id="u1")
# after
m.add([{"role": "user", "content": "hi"}], user_id="u1")
# or the shorthand
m.add("hi", user_id="u1") Defensive patterns
Strategy: type-guard
Validate before calling
if isinstance(messages, tuple):
messages = list(messages)
elif isinstance(messages, str):
messages = [{"role": "user", "content": messages}]
if not isinstance(messages, (str, dict, list)):
raise TypeError(f"messages must be str/dict/list, got {type(messages).__name__}") Type guard
def is_valid_messages(msgs) -> bool:
if isinstance(msgs, (str, dict)):
return True
return isinstance(msgs, list) and all(isinstance(x, dict) for x in msgs) Try / catch
from mem0.memory.utils import Mem0ValidationError
try:
m.add(msgs, user_id=uid)
except Mem0ValidationError as e:
if e.error_code == "VALIDATION_003":
msgs = [msgs] if isinstance(msgs, (str, dict)) else list(msgs)
m.add(msgs, user_id=uid)
else:
raise Prevention
- Normalize collections to list early: list(messages) fixes tuples/generators.
- Pass Python objects, never json.dumps output, as messages.
- Assert the shape in unit tests for wrapper functions.
When it happens
Trigger: m.add(({'role':'user','content':'hi'},)) with a tuple instead of list; m.add(None); passing a generator or map object from a streaming pipeline; passing messages=json.dumps(list_of_dicts) (a str that will be treated as one user message, so ensure you pass the list itself); passing a pandas Series of dicts.
Common situations: Functions that accept *args and build a tuple; streaming chat UIs accumulating messages in a tuple; JSON transport layers that serialize too early; mocking tests with MagicMock payloads.
Related errors
- messages is required and cannot be undefined or null. Provid
- messages array cannot be empty. Provide at least one message
- top_k must be a valid integer
- Invalid query: must be a non-empty string.
- VALIDATION_001
AI-assisted analysis of mem0ai/mem0@001c235229 (2026-08-15).
Data as JSON: /api/errors/af348b339947f659.
Report an issue: GitHub.