deepset-ai/haystack · error · TypeError
Invalid messages type. Expected list[ChatMessage] or str.
Error message
Invalid messages type. Expected list[ChatMessage] or str.
What it means
_normalize_messages accepts either a single string (treated as one user message) or a list of ChatMessage objects. Anything else raises TypeError, which is also surfaced for lists containing non-ChatMessage items.
Source
Thrown at haystack/components/generators/utils.py:225
"""
if hasattr(obj, "model_dump"):
return obj.model_dump()
if hasattr(obj, "__dict__"):
return {k: _serialize_object(v) for k, v in obj.__dict__.items() if not k.startswith("_")}
if isinstance(obj, dict):
return {k: _serialize_object(v) for k, v in obj.items()}
if isinstance(obj, list):
return [_serialize_object(item) for item in obj]
return obj
def _normalize_messages(messages: list[ChatMessage] | str) -> list[ChatMessage]:
"""Normalize messages to a list of ChatMessage objects."""
if isinstance(messages, str):
return [ChatMessage.from_user(messages)]
if isinstance(messages, list) and all(isinstance(msg, ChatMessage) for msg in messages):
return messages
raise TypeError("Invalid messages type. Expected list[ChatMessage] or str.")
View on GitHub (pinned to e318778c9b)
Solutions
- Convert legacy strings: [ChatMessage.from_user(s) for s in list_of_strings]
- Wrap a single ChatMessage in a list: [msg]
- If a dict is passed, convert to ChatMessage via the appropriate constructor
Example fix
// before
llm.run(messages=["hello", "world"])
// after
llm.run(messages=[ChatMessage.from_user("hello"), ChatMessage.from_user("world")]) Defensive patterns
Strategy: type-guard
Validate before calling
if isinstance(messages, str):
messages = [ChatMessage.from_user(messages)]
elif not (isinstance(messages, list) and all(isinstance(m, ChatMessage) for m in messages)):
raise TypeError("Expected list[ChatMessage] or str") Type guard
def is_valid_messages(v) -> bool:
return isinstance(v, str) or (isinstance(v, list) and all(isinstance(m, ChatMessage) for m in v)) Try / catch
try:
gen.run(messages=messages)
except TypeError as e:
if "Invalid messages type" in str(e):
messages = [ChatMessage.from_user(s) for s in messages]
gen.run(messages=messages) Prevention
- Wrap single ChatMessage in a list
- Convert raw strings with ChatMessage.from_user
- Check migration notes when upgrading generators
When it happens
Trigger: Passing a plain dict, a list of strings (e.g. ["hi"]), a single ChatMessage (not wrapped in a list), or None to a generator/util that expects list[ChatMessage] | str.
Common situations: After a version change where a generator switched from accepting str|list[str] to list[ChatMessage]; passing prompt strings or dicts built for other APIs.
Related errors
- 'response_fn' must return a string or ChatMessage, got {type
- Unsupported tool result: {result.result}
- MarkdownHeaderSplitter only works with text documents (str c
- StateSchema: 'messages' must be of type list[ChatMessage], g
- Document with ID '{doc.id}' comes from the PDF file '{resolv
AI-assisted analysis of deepset-ai/haystack@e318778c9b (2026-08-30).
Data as JSON: /api/errors/1493d9aaebe56634.
Report an issue: GitHub.