PrefectHQ/fastmcp · error · TypeError

contents must be str, bytes, or list[ResourceContent], got {

Error message

contents must be str, bytes, or list[ResourceContent], got {type(contents).__name__}

What it means

ResourceResult._normalize_contents only understands str, bytes, list[ResourceContent], and JSON-native scalars/containers (dict, list, tuple, int, float, bool, None). Anything else — a custom object, a set, a datetime, a generator — falls through to this TypeError because the library cannot know how to serialize it.

Source

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

            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:
            uri: The URI of the resource (required by MCP types)

        Returns:
            MCP ReadResourceResult with converted contents
        """
        mcp_contents = [item.to_mcp_resource_contents(uri) for item in self.contents]
        return mcp_types.ReadResourceResult(
            contents=mcp_contents,
            _meta=self.meta,  # type: ignore[call-arg]  # _meta is Pydantic alias for meta field
        )

View on GitHub (pinned to 1f02114297)

Solutions

  1. Convert the value first: json.dumps(value, default=str) wrapped in ResourceContent, or str(value)
  2. Serialize dataclasses/Pydantic models with model_dump()/asdict() before passing
  3. If it's binary, pass bytes directly

Example fix

// before
return ResourceResult(contents=my_dataclass_instance)
// after
return ResourceResult(contents=json.dumps(asdict(my_dataclass_instance), default=str), meta=None)
// or rely on auto-serialization for JSON-native values:
return ResourceResult(contents=my_dataclass_instance.__dict__)
Defensive patterns

Strategy: validation

Validate before calling

JSON_NATIVE = (dict, list, tuple, int, float, bool)
def ok(contents):
    return isinstance(contents, (str, bytes)) or isinstance(contents, JSON_NATIVE) or contents is None
assert ok(payload), f"unsupported contents type: {type(payload).__name__}"

Type guard

def is_serializable_contents(c) -> bool:
    return isinstance(c, (str, bytes, dict, list, tuple, int, float, bool)) or c is None

Try / catch

try:
    return ResourceResult(contents=value)
except TypeError:
    return ResourceResult(contents=json.dumps(value, default=str))

Prevention

When it happens

Trigger: ResourceResult(contents=some_object); ResourceResult(contents={1,2}); ResourceResult(contents=datetime.now()); ResourceResult(contents=(x for x in items)) — any non-str/bytes/list/JSON-native value passed as contents to ResourceResult.__init__.

Common situations: Returning ORM model instances, dataclasses, Decimal, sets, or generators from resource functions; forgetting to json.dumps or str() custom objects before wrapping.

Related errors


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