{"record":{"id":"2621861df18878a4","repo":"agentscope-ai/agentscope","slug":"expected-msg-object-got-type-msg-instead","errorCode":null,"errorMessage":"Expected Msg object, got {type(msg)} instead.","messagePattern":"Expected Msg object, got (.+?) instead\\.","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"src/agentscope/formatter/_formatter_base.py","lineNumber":65,"sourceCode":"    @abstractmethod\n    async def format(self, *args: Any, **kwargs: Any) -> list[dict[str, Any]]:\n        \"\"\"Format the Msg objects to a list of dictionaries that satisfy the\n        API requirements.\"\"\"\n\n    @staticmethod\n    def assert_list_of_msgs(msgs: list[Msg]) -> None:\n        \"\"\"Assert that the input is a list of Msg objects.\n\n        Args:\n            msgs (`list[Msg]`):\n                A list of Msg objects to be validated.\n        \"\"\"\n        if not isinstance(msgs, list):\n            raise TypeError(\"Input must be a list of Msg objects.\")\n\n        for msg in msgs:\n            if not isinstance(msg, Msg):\n                raise TypeError(\n                    f\"Expected Msg object, got {type(msg)} instead.\",\n                )\n\n    @staticmethod\n    def _convert_unsupported_data_block_to_string(block: DataBlock) -> str:\n        \"\"\"Convert an unsupported data block into its textual fallback.\n\n        URL sources remain accessible through their URL. Base64 sources are\n        persisted to a temporary file so the model can still reference the\n        result when the target API cannot carry that media type directly.\n\n        Args:\n            block (`DataBlock`):\n                The unsupported data block to convert.\n\n        Returns:\n            `str`:\n                The textual fallback for the data block.","sourceCodeStart":47,"sourceCodeEnd":83,"githubUrl":"https://github.com/agentscope-ai/agentscope/blob/e90f1c7592896cc95f6e5ee506194f533378247d/src/agentscope/formatter/_formatter_base.py#L47-L83","documentation":"assert_list_of_msgs iterates the input list and raises TypeError when any element is not a Msg instance. This catches mixed or converted histories, e.g. dicts from JSON deserialization or plain strings, before the formatter chokes deeper in processing.","triggerScenarios":"Passing a list like [msg, {\"role\": \"user\", \"content\": \"hi\"}] or [msg, \"hi\"]; loading a conversation from JSON and formatting it without deserializing dicts back to Msg objects.","commonSituations":"Restoring conversations from persistence/JSON; mixing API responses with local Msg objects; helper functions that return content strings instead of Msgs.","solutions":["Deserialize dicts back into Msg objects before formatting (e.g. Msg.from_dict(d))","Filter or map the list so every element is a Msg","Fix the producer that inserts strings/dicts into the history"],"exampleFix":"# before\nformatter.format([{\"role\": \"user\", \"content\": \"hi\"}])\n\n# after\nformatter.format([Msg.from_dict({\"role\": \"user\", \"content\": \"hi\"})])  # or construct Msg(\"user\", \"hi\") directly","handlingStrategy":"validation","validationCode":"msgs = [Msg.from_dict(m) if isinstance(m, dict) else m for m in msgs]\nassert all(isinstance(m, Msg) for m in msgs)","typeGuard":"def is_msg_list(msgs) -> bool:\n    return isinstance(msgs, list) and all(isinstance(m, Msg) for m in msgs)","tryCatchPattern":"try:\n    formatter.format(msgs)\nexcept TypeError as e:\n    if \"Expected Msg object\" in str(e):\n        msgs = [Msg.from_dict(m) if isinstance(m, dict) else m for m in msgs]\n        formatted = formatter.format(msgs)\n    else:\n        raise","preventionTips":["Deserialize persisted conversations back to Msg before formatting","Type-annotate helper functions as list[Msg] so mypy catches this early"],"tags":["validation","typeerror","deserialization","formatter","agentscope"],"backgroundTag":"invalid-argument-type","analyzedSha":"e90f1c7592896cc95f6e5ee506194f533378247d","analyzedAt":"2026-08-28T18:24:12.087Z","schemaVersion":2},"datasetVersion":"2026-08-28T21:17:43.275Z"}