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
- 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
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
- Deserialize persisted conversations back to Msg before formatting
- Type-annotate helper functions as list[Msg] so mypy catches this early
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
- Input must be a list of Msg objects.
- Input validation failed for tool '{tool_call.name}': {e.mess
- The injection template must contain the '{runtime_state}' pl
- Expected a 5-field cron expression, got {record.data.cron_ex
- Unsupported audio source type: {type(source)}
AI-assisted analysis of agentscope-ai/agentscope@e90f1c7592 (2026-08-28).
Data as JSON: /api/errors/2621861df18878a4.
Report an issue: GitHub.