agentscope-ai/agentscope · error · TypeError

Expected Msg object, got {type(msg)} instead.

Error message

Expected Msg object, got {type(msg)} instead.

What it means

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.

Source

Thrown at src/agentscope/formatter/_formatter_base.py:65

    @abstractmethod
    async def format(self, *args: Any, **kwargs: Any) -> list[dict[str, Any]]:
        """Format the Msg objects to a list of dictionaries that satisfy the
        API requirements."""

    @staticmethod
    def assert_list_of_msgs(msgs: list[Msg]) -> None:
        """Assert that the input is a list of Msg objects.

        Args:
            msgs (`list[Msg]`):
                A list of Msg objects to be validated.
        """
        if not isinstance(msgs, list):
            raise TypeError("Input must be a list of Msg objects.")

        for msg in msgs:
            if not isinstance(msg, Msg):
                raise TypeError(
                    f"Expected Msg object, got {type(msg)} instead.",
                )

    @staticmethod
    def _convert_unsupported_data_block_to_string(block: DataBlock) -> str:
        """Convert an unsupported data block into its textual fallback.

        URL sources remain accessible through their URL. Base64 sources are
        persisted to a temporary file so the model can still reference the
        result when the target API cannot carry that media type directly.

        Args:
            block (`DataBlock`):
                The unsupported data block to convert.

        Returns:
            `str`:
                The textual fallback for the data block.

View on GitHub (pinned to e90f1c7592)

Solutions

  1. Deserialize dicts back into Msg objects before formatting (e.g. Msg.from_dict(d))
  2. Filter or map the list so every element is a Msg
  3. Fix the producer that inserts strings/dicts into the history

Example fix

# before
formatter.format([{"role": "user", "content": "hi"}])

# after
formatter.format([Msg.from_dict({"role": "user", "content": "hi"})])  # or construct Msg("user", "hi") directly
Defensive patterns

Strategy: validation

Validate before calling

msgs = [Msg.from_dict(m) if isinstance(m, dict) else m for m in msgs]
assert all(isinstance(m, Msg) for m in msgs)

Type guard

def is_msg_list(msgs) -> bool:
    return isinstance(msgs, list) and all(isinstance(m, Msg) for m in msgs)

Try / catch

try:
    formatter.format(msgs)
except TypeError as e:
    if "Expected Msg object" in str(e):
        msgs = [Msg.from_dict(m) if isinstance(m, dict) else m for m in msgs]
        formatted = formatter.format(msgs)
    else:
        raise

Prevention

When it happens

Trigger: 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.

Common situations: Restoring conversations from persistence/JSON; mixing API responses with local Msg objects; helper functions that return content strings instead of Msgs.

Understand the failure class

Background: Invalid argument type errors: "must be of type string", "expected X, got Y", and ERR_INVALID_ARG_TYPE explained — this error's family across 15 libraries.

Related errors


AI-assisted analysis of agentscope-ai/agentscope@e90f1c7592 (2026-08-28). Data as JSON: /api/errors/2621861df18878a4. Report an issue: GitHub.