PrefectHQ/fastmcp · error · TypeError

Prompt must return str, list[Message], or PromptResult, got

Error message

Prompt must return str, list[Message], or PromptResult, got {type(raw_value).__name__}

What it means

Prompt.convert_result is the final gate for render() output: only str, list[Message|str], or PromptResult are supported. Any other top-level type (dict, None, int, tuple) raises TypeError stating what the prompt returned and what is allowed.

Source

Thrown at fastmcp_slim/fastmcp/prompts/base.py:346

        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, FastMCPProviderPrompt
        overrides this to delegate to child-server middleware.
        """
        result = await self.render(arguments)
        return self.convert_result(result)

    def get_span_attributes(self) -> dict[str, Any]:

View on GitHub (pinned to 1f02114297)

Solutions

  1. Return one of the supported shapes: a str, a list of Message/str, or a PromptResult
  2. Wrap the object: PromptResult([Message(str(raw_value))]) or extract .content from SDK responses
  3. Audit all return paths in render() to ensure none return None

Example fix

// before
def render(self):
    result = build_messages()
    # returns a dict
    return result
// after
def render(self):
    result = build_messages()
    return [Message(m["content"]) for m in result]
Defensive patterns

Strategy: type-guard

Validate before calling

def ensure_convertible(raw) -> object:
    if raw is None or isinstance(raw, dict):
        raise TypeError("render must return str, list[Message|str], or PromptResult")
    return raw

Type guard

def is_valid_render_result(v: object) -> bool:
    if v is None or isinstance(v, PromptResult) or isinstance(v, str):
        return isinstance(v, (PromptResult, str))
    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:
    logger.error("prompt returned unsupported type: %s", e)
    result = prompt.convert_result(str(raw))

Prevention

When it happens

Trigger: render() returns None (e.g. a function whose body forgot to return), a dict (chat-style message), a tuple, or an arbitrary object; an async render returning an unexpected type.

Common situations: Returning OpenAI/Anthropic response objects directly; render with early-return paths that skip the return statement; migration from another prompt framework with different return conventions.

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/869d02b4c3168537. Report an issue: GitHub.