{"record":{"id":"dd09d1be4131eb34","repo":"PrefectHQ/fastmcp","slug":"cannot-determine-tool-name-for-fn-r","errorCode":null,"errorMessage":"Cannot determine tool name for {fn!r}","messagePattern":"Cannot determine tool name for (.+?)","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"fastmcp_slim/fastmcp/apps/app.py","lineNumber":231,"sourceCode":"            @app.tool\n            def save(name: str): ...\n\n            @app.tool()\n            def save(name: str): ...\n\n            @app.tool(\"custom_name\")\n            def save(name: str): ...\n        \"\"\"\n        visibility: list[Literal[\"app\", \"model\"]] = (\n            [\"app\", \"model\"] if model else [\"app\"]\n        )\n\n        def _register(fn: F, tool_name: str | None) -> F:\n            from fastmcp.tools.base import Tool\n\n            resolved_name = tool_name or getattr(fn, \"__name__\", None)\n            if resolved_name is None:\n                raise ValueError(f\"Cannot determine tool name for {fn!r}\")\n\n            from fastmcp.apps.config import AppConfig, app_config_to_meta_dict\n            from fastmcp.server.providers.addressing import (\n                TOOL_HASH_META_KEY,\n                hash_tool,\n            )\n\n            app_config = AppConfig(visibility=visibility)\n            meta: dict[str, Any] = {\n                \"ui\": app_config_to_meta_dict(app_config),\n                \"fastmcp\": {\n                    \"app\": self.name,\n                    TOOL_HASH_META_KEY: hash_tool(self.name, resolved_name),\n                },\n            }\n\n            tool_obj = Tool.from_function(\n                fn,","sourceCodeStart":213,"sourceCodeEnd":249,"githubUrl":"https://github.com/PrefectHQ/fastmcp/blob/1f021142978e0861cd910c8df4e8074bc7cf3978/fastmcp_slim/fastmcp/apps/app.py#L213-L249","documentation":"When registering a tool, its name is taken from the explicit tool_name argument or the callable's __name__. If both are missing (the object has no __name__), _register cannot produce a unique tool name and raises this ValueError.","triggerScenarios":"Registering a callable lacking __name__ (e.g. functools.partial, a callable class instance, a custom decorator that did not use functools.wraps) without passing an explicit name.","commonSituations":"Decorating callables wrapped by third-party libraries; registering method-like objects; minified/proxied functions in tests (Mocks).","solutions":["Pass an explicit tool name: `@app.tool(\"my_tool_name\")`.","Restore __name__ on the callable (use functools.wraps in your decorator, or set `fn.__name__ = ...`).","Register the underlying plain function instead of the wrapper object."],"exampleFix":"// before\n@app.tool()\ndef wrapper(): return partial_fn()\n// after\n@app.tool(\"my_tool\")\ndef my_tool(): ...\n# or: functools.wraps(original) inside the custom decorator","handlingStrategy":"validation","validationCode":"def ensure_nameable(fn, tool_name=None) -> None:\n    if tool_name is None and getattr(fn, \"__name__\", None) is None:\n        raise ValueError(f\"Pass an explicit tool name for {fn!r}\")","typeGuard":"def has_derivable_name(fn) -> bool:\n    return getattr(fn, \"__name__\", None) is not None","tryCatchPattern":"try:\n    app.tool()(fn)\nexcept ValueError as e:\n    if \"Cannot determine tool name\" in str(e):\n        app.tool(\"explicit_name\")(fn)","preventionTips":["Always apply functools.wraps in custom decorators","Give callables a __name__ (even partials) before registering","Pass an explicit name when registering wrapped/anonymous callables"],"tags":["python","valueerror","tool-registration"],"backgroundTag":"tool-name-unresolvable","analyzedSha":"1f021142978e0861cd910c8df4e8074bc7cf3978","analyzedAt":"2026-08-29T14:31:16.082Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}