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
- Convert the value first: json.dumps(value, default=str) wrapped in ResourceContent, or str(value)
- Serialize dataclasses/Pydantic models with model_dump()/asdict() before passing
- 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
- Serialize custom objects (dataclasses, models, Decimal, sets) before passing contents
- Use json.dumps(..., default=str) for anything not JSON-native
- Avoid returning generators or ORM objects from resource functions
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
- contents[{i}] must be ResourceContent, got {type(item).__nam
- Expected Resource, ResourceTemplate, or @resource-decorated
- ResourcesAsTools requires a FastMCP server instance, not a {
- Protocol mode for server {name!r} must be a string
- mcp_tool() got unexpected keyword argument(s): {sorted(unkno
AI-assisted analysis of PrefectHQ/fastmcp@1f02114297 (2026-08-29).
Data as JSON: /api/errors/9cb87c7cce33de06.
Report an issue: GitHub.