PrefectHQ/fastmcp · error · TypeError
messages must be str or list[Message], got {type(messages)._
Error message
messages must be str or list[Message], got {type(messages).__name__} What it means
Prompt._normalize_messages accepts only str or list[Message] for messages. Any other top-level type (dict, tuple, None, list-like objects) raises TypeError naming the actual type received.
Source
Thrown at fastmcp_slim/fastmcp/prompts/base.py:178
super().__init__(messages=normalized, description=description, meta=meta)
@staticmethod
def _normalize_messages(
messages: str | list[Message],
) -> list[Message]:
"""Normalize input to list[Message]."""
if isinstance(messages, str):
return [Message(messages)]
if isinstance(messages, list):
# Validate all items are Message
for i, item in enumerate(messages):
if not isinstance(item, Message):
raise TypeError(
f"messages[{i}] must be Message, got {type(item).__name__}. "
f"Use Message({item!r}) to wrap the value."
)
return messages
raise TypeError(
f"messages must be str or list[Message], got {type(messages).__name__}"
)
def to_mcp_prompt_result(self) -> GetPromptResult:
"""Convert to MCP GetPromptResult."""
mcp_messages = [m.to_mcp_prompt_message() for m in self.messages]
return GetPromptResult(
description=self.description,
messages=mcp_messages,
_meta=self.meta, # type: ignore[call-arg] # _meta is Pydantic alias for meta field
)
class InputRequiredPromptResult(PromptResult):
"""The full result of a single multi-round-trip prompt leg (SEP-2322).
`InputRequiredResult` is a result type, not a `tools/call` feature: any
request may resolve to one. When a prompt returns an `InputRequiredResult`View on GitHub (pinned to 1f02114297)
Solutions
- Convert dicts to Message objects or use the documented str/list[Message] shapes
- Wrap sequence in a list: list(messages)
- Build Message objects from deserialized data before constructing Prompt
Example fix
// before
Prompt(name="p", messages={"role": "user", "content": "hi"})
// after
Prompt(name="p", messages=[Message("hi")]) Defensive patterns
Strategy: type-guard
Validate before calling
def normalize_top_level(msgs) -> list[Message]:
if isinstance(msgs, str):
return [Message(msgs)]
if not isinstance(msgs, list):
raise TypeError("messages must be str or list[Message]")
return [m if isinstance(m, Message) else Message(m) for m in msgs] Type guard
def is_str_or_message_list(v: object) -> bool:
return isinstance(v, (str, list)) Try / catch
try:
prompt = Prompt(name=name, messages=msgs)
except TypeError:
prompt = Prompt(name=name, messages=[Message(json.dumps(msgs))]) # or correct the type Prevention
- Pass lists, not tuples/dicts/generators
- Convert chat-style dicts to Message before constructing Prompt
- Add unit tests asserting Prompt construction types
When it happens
Trigger: Prompt(..., messages={"role": "user", "content": "hi"}) (dict), messages=("a","b") (tuple), messages=None, or a non-list sequence.
Common situations: Passing chat-completion-style dicts; passing a generator or tuple of Messages; JSON deserialization producing dicts instead of Message objects.
Understand the failure class
Background: "Wrong argument type", "must be a string", "expected Array or Prism::Scope": TypeError and ArgumentError when a library receives a value of the wrong type — this error's family across 28 libraries.
Related errors
- messages[{i}] must be Message, got {type(item).__name__}. Us
- messages[{i}] must be Message or str, got {type(item).__name
- Protocol mode for server {name!r} must be a string
- Prompt must return str, list[Message], or PromptResult, got
- Expected Prompt or @prompt-decorated function, got {type(pro
AI-assisted analysis of PrefectHQ/fastmcp@1f02114297 (2026-08-29).
Data as JSON: /api/errors/5d81a8372c35d5a2.
Report an issue: GitHub.