{"record":{"id":"607e35ce48b22a92","repo":"PrefectHQ/fastmcp","slug":"subclasses-must-implement-run","errorCode":null,"errorMessage":"Subclasses must implement run()","messagePattern":"Subclasses must implement run\\(\\)","errorType":"exception","errorClass":"NotImplementedError","httpStatus":null,"severity":"error","filePath":"fastmcp_slim/fastmcp/tools/base.py","lineNumber":365,"sourceCode":"        )\n\n    async def run(self, arguments: dict[str, Any]) -> ToolResult:\n        \"\"\"\n        Run the tool with arguments.\n\n        This method is not implemented in the base Tool class and must be\n        implemented by subclasses.\n\n        `run()` can EITHER return a list of ContentBlocks, or a tuple of\n        (list of ContentBlocks, dict of structured output).\n\n        A tool that requests client input (SEP-2322 multi-round-trip) does so by\n        returning an `InputRequiredResult` from its body; the run machinery wraps\n        that in an `InputRequiredToolResult` — a `ToolResult` subclass — so it\n        stays inside the declared `ToolResult` result type and flows through the\n        middleware chain as an ordinary result (see `FunctionTool.run`).\n        \"\"\"\n        raise NotImplementedError(\"Subclasses must implement run()\")\n\n    def convert_result(self, raw_value: Any) -> ToolResult:\n        \"\"\"Convert a raw result to ToolResult.\n\n        Handles ToolResult passthrough and converts raw values using the tool's\n        attributes (output_schema) for proper conversion.\n        \"\"\"\n        if isinstance(raw_value, ToolResult):\n            return raw_value\n\n        if isinstance(raw_value, CallToolResult):\n            return ToolResult.from_mcp_result(raw_value)\n\n        if is_prefab_app(raw_value):\n            return _prefab_to_tool_result(\n                raw_value,\n                fastmcp_app_name=_get_fastmcp_app_name(self),\n            )","sourceCodeStart":347,"sourceCodeEnd":383,"githubUrl":"https://github.com/PrefectHQ/fastmcp/blob/1f021142978e0861cd910c8df4e8074bc7cf3978/fastmcp_slim/fastmcp/tools/base.py#L347-L383","documentation":"Tool is an abstract base class; `run()` is the abstract method every concrete tool must implement to execute and produce a ToolResult. Calling `run()` on a subclass that didn't override it raises NotImplementedError. The base class deliberately fails fast instead of silently returning nothing.","triggerScenarios":"Subclassing `Tool` (or another Tool subclass) and implementing only `_run`/metadata without overriding `run()`; calling `run()` on the base class or an incomplete subclass instance; refactoring that renamed an override so it no longer binds as `run`.","commonSituations":"Custom tool abstractions layered on top of FastMCP that only override internal hooks; after a library upgrade, an inherited class whose overridden method was renamed (run vs _run contract change); instantiating an abstract-like helper class directly in tests.","solutions":["Implement `run(self, context) -> ToolResult` in your subclass.","Prefer subclassing `FunctionTool` and using `from_function` rather than implementing Tool from scratch.","After upgrades, check whether your override should be `run` vs `_run` and rename accordingly.","Make custom base classes themselves raise early or be ABCs so misuse is caught at instantiation."],"exampleFix":"# before\nclass MyTool(Tool):\n    def _run(self, ctx):\n        ...\n# after\nclass MyTool(Tool):\n    async def run(self, context):\n        return ToolResult(content=\"done\")","handlingStrategy":"validation","validationCode":"def ensure_concrete(tool_cls) -> bool:\n    return getattr(tool_cls.run, \"__isabstractmethod__\", False) is not True and \\\n           not (getattr(tool_cls.run, \"__qualname__\", \"\").startswith(\"Tool.\"))","typeGuard":null,"tryCatchPattern":"try:\n    result = await tool.run(ctx)\nexcept NotImplementedError:\n    raise TypeError(f\"{type(tool).__name__} does not implement run()\")","preventionTips":["Use abc.ABC / @abstractmethod on custom base classes to fail at instantiation.","Subclass FunctionTool instead of the abstract Tool base.","After upgrades, grep custom tools for `def _run` and confirm the run/_run contract."],"tags":["python","notimplementederror","abstract-method","tool","subclass"],"backgroundTag":"abstract-method-not-implemented","analyzedSha":"1f021142978e0861cd910c8df4e8074bc7cf3978","analyzedAt":"2026-08-29T14:31:16.082Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}