{"record":{"id":"0b94799c6ec0c73a","repo":"PrefectHQ/fastmcp","slug":"subclasses-must-implement-read","errorCode":null,"errorMessage":"Subclasses must implement read()","messagePattern":"Subclasses must implement read\\(\\)","errorType":"exception","errorClass":"NotImplementedError","httpStatus":null,"severity":"error","filePath":"fastmcp_slim/fastmcp/resources/base.py","lineNumber":423,"sourceCode":"        if self.name:\n            pass\n        elif self.uri:\n            self.name = str(self.uri)\n        else:\n            raise ValueError(\"Either name or uri must be provided\")\n        return self\n\n    async def read(\n        self,\n    ) -> str | bytes | ResourceResult:\n        \"\"\"Read the resource content.\n\n        Subclasses implement this to return resource data. Supported return types:\n            - str: Text content\n            - bytes: Binary content\n            - ResourceResult: Full control over contents and result-level meta\n        \"\"\"\n        raise NotImplementedError(\"Subclasses must implement read()\")\n\n    def convert_result(self, raw_value: Any) -> ResourceResult:\n        \"\"\"Convert a raw result to ResourceResult.\n\n        This is used in two contexts:\n        1. In _read() to convert user function return values to ResourceResult\n        2. In tasks_result_handler() to convert Docket task results to ResourceResult\n\n        Handles ResourceResult passthrough and converts raw values using\n        ResourceResult's normalization.  When the raw value is a plain\n        string or bytes, the resource's own ``mime_type`` is forwarded so\n        that ``ui://`` resources (and others with non-default MIME types)\n        don't fall back to ``text/plain``.\n\n        The resource's component-level ``meta`` (e.g. ``ui`` metadata for\n        MCP Apps CSP/permissions) is propagated to each content item so\n        that hosts can read it from the ``resources/read`` response.\n        \"\"\"","sourceCodeStart":405,"sourceCodeEnd":441,"githubUrl":"https://github.com/PrefectHQ/fastmcp/blob/1f021142978e0861cd910c8df4e8074bc7cf3978/fastmcp_slim/fastmcp/resources/base.py#L405-L441","documentation":"Resource.read() is an abstract-ish base method: the base Resource class cannot produce data on its own, so subclasses (FunctionResource, FileResource, etc.) must implement read(). Instantiating a custom Resource subclass without overriding read() leads to this NotImplementedError at read time (raised via _read).","triggerScenarios":"class MyResource(Resource): pass then calling mcp.read_resource or MyResource().read(); a subclass overriding other hooks but not read().","commonSituations":"Custom resource subclasses where the author implemented __init__ or convert_result but forgot the async read() method; refactoring that renamed read accidentally.","solutions":["Implement async def read(self) in your subclass returning str, bytes, or ResourceResult","Or subclass/contribute via FunctionResource(fn) instead of extending Resource directly","If you meant a template, implement ResourceTemplate.read()/create_resource() instead"],"exampleFix":"// before\nclass DbResource(Resource):\n    pass  # read() missing\n// after\nclass DbResource(Resource):\n    async def read(self):\n        return fetch_data()","handlingStrategy":"validation","validationCode":"import inspect\nassert inspect.iscoroutinefunction(MyResource.read), \"subclass must implement async read()\"","typeGuard":"def implements_read(cls) -> bool:\n    return getattr(cls.read, \"__qualname__\", \"\") != \"Resource.read\"","tryCatchPattern":"try:\n    content = await resource.read()\nexcept NotImplementedError:\n    logging.error(f\"{type(resource).__name__} does not implement read()\")\n    raise","preventionTips":["Subclass a concrete type (FunctionResource, FileResource) rather than base Resource","Test custom resource subclasses with an actual read in CI","Avoid renaming read() during refactors; it's part of the base contract"],"tags":["python","resources","not-implemented"],"backgroundTag":"subclass-must-implement-method","analyzedSha":"1f021142978e0861cd910c8df4e8074bc7cf3978","analyzedAt":"2026-08-29T14:31:16.082Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}