PrefectHQ/fastmcp · error

Either content or structured_content must be provided

Error message

Either content or structured_content must be provided

What it means

ToolResult requires at least one of `content` or `structured_content`. A result with neither would be an empty tool response, which MCP tools should never emit; the constructor raises ValueError to catch this at construction time rather than sending an empty result to the client.

Source

Thrown at fastmcp_slim/fastmcp/tools/base.py:122

    meta: dict[str, Any] | None = Field(
        default=None, description="Runtime metadata about the tool execution"
    )
    is_error: bool = Field(
        default=False,
        description="Whether this result represents a tool execution error. "
        "When True, it maps to CallToolResult.is_error so the error is returned "
        "to the client rather than raised.",
    )

    def __init__(
        self,
        content: list[ContentBlock] | Any | None = None,
        structured_content: dict[str, Any] | Any | None = None,
        meta: dict[str, Any] | None = None,
        is_error: bool = False,
    ):
        if content is None and structured_content is None:
            raise ValueError("Either content or structured_content must be provided")
        elif content is None:
            content = structured_content

        converted_content: list[ContentBlock] = _convert_to_content(result=content)

        if structured_content is not None:
            # Convert Prefab types to their wire-format envelope before
            # generic serialization, so the renderer gets the right shape.
            if is_prefab_app(structured_content):
                structured_content = _prefab_to_json(structured_content)
            elif is_prefab_component(structured_content):
                structured_content = _prefab_to_json(
                    prefab_app_from_component(structured_content)
                )

            try:
                structured_content = _serialize_to_jsonable(structured_content)
            except pydantic_core.PydanticSerializationError as e:

View on GitHub (pinned to 1f02114297)

Solutions

  1. Return an explicit value from the tool (e.g. a string message or dict) instead of None.
  2. For intentionally empty results, pass a sentinel like `content=""` or an empty dict for structured_content.
  3. Ensure tools declare an output_schema so unstructured None returns are wrapped/validated instead of passed through.
  4. In result-building code, assert/log when both inputs are None before constructing ToolResult.

Example fix

# before
return ToolResult(content=None, structured_content=None)
# after
return ToolResult(content="No results found.")
Defensive patterns

Strategy: validation

Validate before calling

def safe_tool_result(content=None, structured_content=None, **kw):
    if content is None and structured_content is None:
        content = ""  # or raise/handle per your contract
    return ToolResult(content=content, structured_content=structured_content, **kw)

Try / catch

try:
    result = ToolResult(content=fn_output, structured_content=sc)
except ValueError:
    result = ToolResult(content="(no output)")

Prevention

When it happens

Trigger: `ToolResult()` with no arguments, or `ToolResult(content=None, structured_content=None)` — usually from a tool function returning None, or code constructing a result from variables that both ended up None (e.g. an unhandled empty branch).

Common situations: Tool functions that fall through without returning; wrappers that forward an optional value which is None; conditional result-building code where every branch forgot to set a payload.

Related errors


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