PrefectHQ/fastmcp · error · TypeError
messages[{i}] must be Message or str, got {type(item).__name
Error message
messages[{i}] must be Message or str, got {type(item).__name__}. Use Message({item!r}) to wrap the value. What it means
Prompt.convert_result accepts only PromptResult, str, or list of Message/str as a render return value. Inside a list, any item that is not a Message or str raises TypeError at that index, prompting you to wrap it with Message(...).
Source
Thrown at fastmcp_slim/fastmcp/prompts/base.py:340
if isinstance(raw_value, mcp_types.InputRequiredResult):
# The prompt asked the client for input (SEP-2322). Wrap it so the
# ask travels the middleware chain as an ordinary result; the wire
# handler unwraps it.
return InputRequiredPromptResult(raw_value)
if isinstance(raw_value, str):
return PromptResult(raw_value, description=self.description, meta=self.meta)
if isinstance(raw_value, list | tuple):
messages: list[Message] = []
for i, item in enumerate(raw_value):
if isinstance(item, Message):
messages.append(item)
elif isinstance(item, str):
messages.append(Message(item))
else:
raise TypeError(
f"messages[{i}] must be Message or str, got {type(item).__name__}. "
f"Use Message({item!r}) to wrap the value."
)
return PromptResult(messages, description=self.description, meta=self.meta)
raise TypeError(
f"Prompt must return str, list[Message], or PromptResult, "
f"got {type(raw_value).__name__}"
)
async def _render(
self,
arguments: dict[str, Any] | None = None,
) -> PromptResult:
"""Server entry point for prompt renders.
The server calls this method instead of render() directly so that
subclasses can customize dispatch. For example, FastMCPProviderPromptView on GitHub (pinned to 1f02114297)
Solutions
- Wrap non-str items in Message(...) inside the returned list
- Return a plain str or PromptResult instead of a heterogeneous list
- Sanitize the list before returning: [it if isinstance(it,(Message,str)) else Message(str(it)) for it in items]
Example fix
// before
return ["hello", {"role": "user", "content": "bye"}]
// after
return [Message("hello"), Message("bye")] Defensive patterns
Strategy: type-guard
Validate before calling
def safe_render_list(items) -> list:
out = []
for it in items:
if isinstance(it, (Message, str)):
out.append(it)
else:
out.append(Message(str(it)))
return out Type guard
def is_message_or_str_list(v: object) -> bool:
return isinstance(v, list) and all(isinstance(i, (Message, str)) for i in v) Try / catch
try:
result = prompt.convert_result(raw)
except TypeError as e:
raw = [Message(str(x)) for x in raw]
result = prompt.convert_result(raw) Prevention
- Return only str/Message items from render()
- Never return raw LLM SDK dicts from render
- Annotate render() return types so type checkers catch bad items
When it happens
Trigger: A prompt's render() returns a list containing ints, dicts, Messages from a different library, tuples, or None — e.g. return ["hi", {"role": "user", "content": "x"}].
Common situations: Returning LLM SDK message dicts directly from render; returning template parts of mixed types; returning results of splitting a string into non-str 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 must be str or list[Message], got {type(messages)._
- 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/fa92ce2af84b8b6a.
Report an issue: GitHub.