PrefectHQ/fastmcp · error · TypeError
messages[{i}] must be Message, got {type(item).__name__}. Us
Error message
messages[{i}] must be Message, got {type(item).__name__}. Use Message({item!r}) to wrap the value. What it means
Prompt._normalize_messages enforces that the messages argument is either a plain string or a list whose every element is a Message instance. A list containing any other type (str, dict, etc.) raises TypeError, telling you exactly which index failed and to wrap the value with Message(...).
Source
Thrown at fastmcp_slim/fastmcp/prompts/base.py:173
messages: String or list of Message objects.
description: Optional description of the prompt result.
meta: Optional metadata about the prompt result.
"""
normalized = self._normalize_messages(messages)
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
)
View on GitHub (pinned to 1f02114297)
Solutions
- Wrap each item: Message("hello") instead of "hello"
- Pass a single string if the prompt is one user message: Prompt(..., messages="hello")
- Convert loaded data: messages=[Message(m) if isinstance(m, str) else m for m in items]
Example fix
// before
Prompt(name="greet", messages=["hello", Message("bye")])
// after
Prompt(name="greet", messages=[Message("hello"), Message("bye")]) Defensive patterns
Strategy: type-guard
Validate before calling
def ensure_messages(msgs) -> list[Message]:
if isinstance(msgs, str):
return [Message(msgs)]
if isinstance(msgs, list) and all(isinstance(m, Message) for m in msgs):
return msgs
raise TypeError("messages must be str or list[Message]") Type guard
def is_valid_messages(v: object) -> bool:
return isinstance(v, str) or (isinstance(v, list) and all(isinstance(i, Message) for i in v)) Try / catch
try:
prompt = Prompt(name=name, messages=msgs)
except TypeError as e:
msgs = [Message(m) if isinstance(m, str) else m for m in msgs]
prompt = Prompt(name=name, messages=msgs) Prevention
- Always wrap plain strings in Message() when building lists
- Validate deserialized prompt data types before constructing Prompt
- Type-annotate messages as list[Message] so checkers catch raw strings
When it happens
Trigger: Prompt(..., messages=["hello"]) — a list of raw strings; mixing Message and str items; passing dicts or tuples in the list; constructing Prompt programmatically from serialized data.
Common situations: Loading prompts from JSON/YAML where items deserialize to dicts/strings; refactors after upgrading where str items were previously auto-wrapped; authors passing openai-style message dicts.
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 must be str or list[Message], got {type(messages)._
- 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/eaac6ebeb65b5183.
Report an issue: GitHub.