PrefectHQ/fastmcp · error · NotImplementedError

Subclasses must implement read() or override create_resource

Error message

Subclasses must implement read() or override create_resource()

What it means

ResourceTemplate.read() is the base-class placeholder: a template must know how to render content for a matched URI. Subclasses that don't override read() (or supply content via create_resource()) hit this NotImplementedError when a client reads a URI matching the template.

Source

Thrown at fastmcp_slim/fastmcp/resources/template.py:265

            auth=auth,
            security=security,
        )

    @field_validator("mime_type", mode="before")
    @classmethod
    def set_default_mime_type(cls, mime_type: str | None) -> str:
        """Set default MIME type if not provided."""
        if mime_type:
            return mime_type
        return "text/plain"

    def matches(self, uri: str) -> dict[str, Any] | None:
        """Check if URI matches template and extract parameters."""
        return match_uri_template(uri, self.uri_template)

    async def read(self, arguments: dict[str, Any]) -> str | bytes | ResourceResult:
        """Read the resource content."""
        raise NotImplementedError(
            "Subclasses must implement read() or override create_resource()"
        )

    def convert_result(self, raw_value: Any) -> ResourceResult:
        """Convert a raw result to ResourceResult.

        This is used in two contexts:
        1. In _read() to convert user function return values to ResourceResult
        2. In tasks_result_handler() to convert Docket task results to ResourceResult

        Handles ResourceResult passthrough and converts raw values using
        ResourceResult's normalization. The template's own ``mime_type`` is
        forwarded so that reads match the MIME type the template advertises
        in ``resources/templates/list``.
        """
        return convert_raw_to_resource_result(
            raw_value, mime_type=self.mime_type, meta=self.meta
        )

View on GitHub (pinned to 1f02114297)

Solutions

  1. Implement async def read(self, arguments) in the subclass returning str, bytes, or ResourceResult
  2. Or override create_resource(uri, params) to build a concrete Resource whose read() supplies content
  3. Prefer FunctionResourceTemplate(fn) for function-backed templates

Example fix

// before
class ApiTemplate(ResourceTemplate):
    def __init__(self, uri_template): super().__init__(uri_template=uri_template)
// after
class ApiTemplate(ResourceTemplate):
    async def read(self, arguments):
        return fetch_api(arguments)
Defensive patterns

Strategy: type-guard

Validate before calling

import inspect
assert inspect.iscoroutinefunction(MyTemplate.read), "template must implement async read()"

Type guard

def implements_template_read(cls) -> bool:
    return getattr(cls.read, "__qualname__", "") != "ResourceTemplate.read"

Try / catch

try:
    content = await template.read(params)
except NotImplementedError:
    raise ConfigurationError(f"{type(template).__name__} lacks read()")

Prevention

When it happens

Trigger: Subclassing ResourceTemplate with a custom matches()/uri_template but no read(arguments) override, then calling read on a matching URI via _read.

Common situations: Custom template types (database-backed, API-backed) where the author implemented matching but not rendering; copying the base class skeleton verbatim.

Related errors


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