{"record":{"id":"efa78e9a3cc3f8e7","repo":"deepset-ai/haystack","slug":"each-response-must-be-a-string-or-chatmessage-got","errorCode":null,"errorMessage":"Each response must be a string or ChatMessage, got {type(item)}.","messagePattern":"Each response must be a string or ChatMessage, got (.+?)\\.","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"haystack/components/generators/chat/mock.py","lineNumber":169,"sourceCode":"            items = list(responses)\n        else:\n            raise TypeError(f\"'responses' must be a string, ChatMessage, or a sequence of them, got {type(responses)}.\")\n\n        if len(items) == 0:\n            raise ValueError(\"'responses' must not be an empty list.\")\n\n        normalized: list[ChatMessage] = []\n        for item in items:\n            if isinstance(item, str):\n                normalized.append(ChatMessage.from_assistant(item))\n            elif isinstance(item, ChatMessage):\n                if item.role != ChatRole.ASSISTANT:\n                    raise ValueError(\n                        f\"Each ChatMessage response must have the 'assistant' role, got '{item.role.value}'.\"\n                    )\n                normalized.append(item)\n            else:\n                raise TypeError(f\"Each response must be a string or ChatMessage, got {type(item)}.\")\n        return normalized\n\n    def to_dict(self) -> dict[str, Any]:\n        \"\"\"Serialize the component to a dictionary.\"\"\"\n        responses = [msg.to_dict() for msg in self._responses] if self._responses is not None else None\n        response_fn = serialize_callable(self.response_fn) if self.response_fn is not None else None\n        streaming_callback = serialize_callable(self.streaming_callback) if self.streaming_callback else None\n        return default_to_dict(\n            self,\n            responses=responses,\n            response_fn=response_fn,\n            model=self.model,\n            meta=self.meta,\n            streaming_callback=streaming_callback,\n        )\n\n    @classmethod\n    def from_dict(cls, data: dict[str, Any]) -> MockChatGenerator:","sourceCodeStart":151,"sourceCodeEnd":187,"githubUrl":"https://github.com/deepset-ai/haystack/blob/e318778c9bf60a1963e3b5f451359655dd696c30/haystack/components/generators/chat/mock.py#L151-L187","documentation":"Inside a `responses` sequence, each element must be a string or a ChatMessage. Any other item type (dict, int, None, bytes) raises TypeError naming the item's type, raised from _normalize_responses during __init__.","triggerScenarios":"`MockChatGenerator(responses=[{\"text\": \"hi\"}])` or [None], or a list mixing strings with dicts/ints — often from JSON-loaded data where ChatMessages deserialize as dicts.","commonSituations":"Loading canned responses from JSON/YAML fixtures and forgetting to call ChatMessage.from_dict; building mixed lists programmatically; passing raw message dicts from another framework.","solutions":["Convert dicts with ChatMessage.from_dict(d) before passing","Use plain strings for simple text replies","Sanitize/mixed lists: map each item through str/ChatMessage.from_dict as appropriate"],"exampleFix":"// before\nmock = MockChatGenerator(responses=[{\"text\": \"hi\", \"role\": \"assistant\"}])\n// after\nmock = MockChatGenerator(responses=[ChatMessage.from_dict({\"text\": \"hi\", \"role\": \"assistant\"})])","handlingStrategy":"type-guard","validationCode":"def coerce_responses(items) -> list[ChatMessage]:\n    out = []\n    for i in items:\n        if isinstance(i, str):\n            out.append(ChatMessage.from_assistant(i))\n        elif isinstance(i, ChatMessage):\n            out.append(i)\n        elif isinstance(i, dict):\n            out.append(ChatMessage.from_dict(i))\n        else:\n            raise TypeError(f\"bad response item: {type(i)}\")\n    return out","typeGuard":"def is_response_item(i) -> bool:\n    return isinstance(i, (str, ChatMessage))","tryCatchPattern":null,"preventionTips":["Deserialize stored responses with ChatMessage.from_dict before passing","Keep fixture lists homogeneous: all strings or all ChatMessages","Annotate response builders with list[str | ChatMessage] return types"],"tags":["mock","type-error","chat-message","testing"],"backgroundTag":"type-mismatch","analyzedSha":"e318778c9bf60a1963e3b5f451359655dd696c30","analyzedAt":"2026-08-30T11:45:20.711Z","schemaVersion":2},"datasetVersion":"2026-08-30T13:17:10.514Z"}