PrefectHQ/fastmcp · error · TypeError

contents[{i}] must be ResourceContent, got {type(item).__nam

Error message

contents[{i}] must be ResourceContent, got {type(item).__name__}. Use ResourceContent({item!r}) to wrap the value.

What it means

ResourceResult._normalize_contents accepts str, bytes, or a list of ResourceContent objects. When you pass a list, every element must already be a ResourceContent instance; a plain str/int/dict inside the list triggers this TypeError. Unlike a bare JSON-native value, lists are not auto-wrapped element-wise because mixed content (text + binary) requires explicit types.

Source

Thrown at fastmcp_slim/fastmcp/resources/base.py:182

            meta: Optional metadata about the resource result.
        """
        normalized = self._normalize_contents(contents)
        super().__init__(contents=normalized, meta=meta)

    @staticmethod
    def _normalize_contents(
        contents: str | bytes | list[ResourceContent],
    ) -> list[ResourceContent]:
        """Normalize input to list[ResourceContent]."""
        if isinstance(contents, str):
            return [ResourceContent(contents)]
        if isinstance(contents, bytes):
            return [ResourceContent(contents)]
        if isinstance(contents, list):
            # Validate all items are ResourceContent
            for i, item in enumerate(contents):
                if not isinstance(item, ResourceContent):
                    raise TypeError(
                        f"contents[{i}] must be ResourceContent, got {type(item).__name__}. "
                        f"Use ResourceContent({item!r}) to wrap the value."
                    )
            return contents
        # Auto-serialize JSON-native types to JSON text
        if (
            isinstance(contents, dict | list | tuple | int | float | bool)
            or contents is None
        ):
            return [ResourceContent(json.dumps(contents), mime_type="application/json")]
        raise TypeError(
            f"contents must be str, bytes, or list[ResourceContent], got {type(contents).__name__}"
        )

    def to_mcp_result(self, uri: AnyUrl | str) -> mcp_types.ReadResourceResult:
        """Convert to MCP ReadResourceResult.

        Args:

View on GitHub (pinned to 1f02114297)

Solutions

  1. Wrap each list element in ResourceContent: contents=[ResourceContent(s) for s in strings]
  2. If the whole value is a single JSON-native value (dict/int/None etc.), pass it directly instead of a list — it will be auto-serialized with mime_type application/json
  3. If the item is already a TextResource/other content object, convert via its text/bytes into ResourceContent

Example fix

// before
return ResourceResult(contents=["hello", b"bin"])
// after
return ResourceResult(contents=[ResourceContent("hello"), ResourceContent(b"bin")])
Defensive patterns

Strategy: type-guard

Validate before calling

def is_valid_contents(c):
    return isinstance(c, (str, bytes)) or (
        isinstance(c, list) and all(isinstance(i, ResourceContent) for i in c)
    )
assert is_valid_contents(my_contents)

Type guard

def as_content_list(items) -> list[ResourceContent]:
    return [i if isinstance(i, ResourceContent) else ResourceContent(i) for i in items]

Try / catch

try:
    result = ResourceResult(contents=items)
except TypeError as e:
    items = [ResourceContent(i) for i in items]
    result = ResourceResult(contents=items)

Prevention

When it happens

Trigger: ResourceResult(contents=["plain string"]); ResourceResult(contents=[b'bytes']); ResourceResult(contents=[{"a":1}]) — any list containing raw values instead of ResourceContent objects, e.g. returned from a @mcp.resource function body.

Common situations: Developers migrating from APIs that accepted raw strings/bytes lists, or returning [item1, item2] from multiple fetches without wrapping each in ResourceContent. Also common when the wrap-suggestion in the message is copy-pasted but the value is a dict whose repr isn't valid code.

Related errors


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