deepset-ai/haystack · error · TypeError
'responses' must be a string, ChatMessage, or a sequence of
Error message
'responses' must be a string, ChatMessage, or a sequence of them, got {type(responses)}. What it means
MockChatGenerator._normalize_responses only accepts a single string, a single ChatMessage, or a sequence (list/tuple) of those. Any other type (dict, int, a set, a generator-like object not a Sequence) raises TypeError naming the offending type.
Source
Thrown at haystack/components/generators/chat/mock.py:153
self.streaming_callback = streaming_callback
self._call_count = 0
self._is_warmed_up = False
@staticmethod
def _normalize_responses(
responses: str | ChatMessage | Sequence[str | ChatMessage] | None,
) -> list[ChatMessage] | None:
"""Normalize the `responses` argument into a non-empty list of `ChatMessage`, or `None` for echo mode."""
if responses is None:
return None
items: list[str | ChatMessage]
if isinstance(responses, (str, ChatMessage)):
items = [responses]
elif isinstance(responses, Sequence):
items = list(responses)
else:
raise TypeError(f"'responses' must be a string, ChatMessage, or a sequence of them, got {type(responses)}.")
if len(items) == 0:
raise ValueError("'responses' must not be an empty list.")
normalized: list[ChatMessage] = []
for item in items:
if isinstance(item, str):
normalized.append(ChatMessage.from_assistant(item))
elif isinstance(item, ChatMessage):
if item.role != ChatRole.ASSISTANT:
raise ValueError(
f"Each ChatMessage response must have the 'assistant' role, got '{item.role.value}'."
)
normalized.append(item)
else:
raise TypeError(f"Each response must be a string or ChatMessage, got {type(item)}.")
return normalized
View on GitHub (pinned to e318778c9b)
Solutions
- Wrap a single value in a list: responses=["my reply"]
- Use a list of strings or ChatMessages: responses=[ChatMessage.from_assistant("hi")]
- If you have a dict, convert to a list of ChatMessages yourself or use response_fn
- Check the variable actually holds the list you think (print/log type before constructing)
Example fix
// before
mock = MockChatGenerator(responses="hi") # actually valid only if str; dicts raise
mock = MockChatGenerator(responses={"a": "b"})
// after
mock = MockChatGenerator(responses=[ChatMessage.from_assistant("b")]) Defensive patterns
Strategy: type-guard
Validate before calling
if not isinstance(responses, (str, ChatMessage, Sequence)):
raise TypeError(f"responses must be str, ChatMessage, or sequence, got {type(responses)}") Type guard
def is_valid_responses(r) -> bool:
if isinstance(r, (str, ChatMessage)):
return True
return isinstance(r, Sequence) and all(isinstance(i, (str, ChatMessage)) for i in r) Prevention
- Always pass a list: responses=[...], even for a single reply
- Convert dict-based fixtures to ChatMessage objects at load time
- Type-annotate responses: list[str | ChatMessage]
When it happens
Trigger: Calling `MockChatGenerator(responses={...})` or with a non-iterable scalar like an int/float, or with a custom object masquerading as a response list.
Common situations: Passing a dict of {prompt: reply} expecting dict support; JSON round-trips turning the list into another type; typos like responses="hi" split incorrectly or responses=True.
Related errors
- {name} must be a sequence of numbers, got {type(value)}.
- Pass either 'responses' or 'response_fn', not both.
- 'responses' must not be an empty list.
- Each ChatMessage response must have the 'assistant' role, go
- Each response must be a string or ChatMessage, got {type(ite
AI-assisted analysis of deepset-ai/haystack@e318778c9b (2026-08-30).
Data as JSON: /api/errors/8f2133a6264c547e.
Report an issue: GitHub.