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

  1. Wrap each item: Message("hello") instead of "hello"
  2. Pass a single string if the prompt is one user message: Prompt(..., messages="hello")
  3. 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

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


AI-assisted analysis of PrefectHQ/fastmcp@1f02114297 (2026-08-29). Data as JSON: /api/errors/eaac6ebeb65b5183. Report an issue: GitHub.