{"record":{"id":"1d8e5fdaa12a0fc7","repo":"PrefectHQ/fastmcp","slug":"ambiguous-app-tool-tool-name-r-len-matches-c","errorCode":null,"errorMessage":"Ambiguous app tool {tool_name!r}: {len(matches)} components share the identity {tool_hash!r}. The same app is composed more than once, so this call cannot be routed to a single tool.","messagePattern":"Ambiguous app tool (.+?): (.+?) components share the identity (.+?)\\. The same app is composed more than once, so this call cannot be routed to a single tool\\.","errorType":"exception","errorClass":"ToolError","httpStatus":null,"severity":"error","filePath":"fastmcp_slim/fastmcp/server/providers/aggregate.py","lineNumber":253,"sourceCode":"        it looking for a missing registration instead of a duplicate one.\n        \"\"\"\n        results = await gather(\n            (p.get_tool_by_hash(tool_hash, tool_name) for p in self.providers),\n            return_exceptions=True,\n        )\n        matches: list[Tool] = []\n        for r in results:\n            if isinstance(r, BaseException):\n                if isinstance(r, ToolError) or self.provider_error_strategy == \"raise\":\n                    raise r\n                continue\n            if r is not None:\n                matches.append(r)\n\n        if not matches:\n            return None\n        if len(matches) > 1:\n            raise ToolError(\n                f\"Ambiguous app tool {tool_name!r}: {len(matches)} components share \"\n                f\"the identity {tool_hash!r}. The same app is composed more than \"\n                f\"once, so this call cannot be routed to a single tool.\"\n            )\n        return matches[0]\n\n    # -------------------------------------------------------------------------\n    # Resources\n    # -------------------------------------------------------------------------\n\n    async def _list_resources(self) -> Sequence[Resource]:\n        \"\"\"List all resources from all providers.\"\"\"\n        results = await gather(\n            (p.list_resources() for p in self.providers),\n            return_exceptions=True,\n        )\n        return self._collect_list_results(results, \"list_resources\")\n","sourceCodeStart":235,"sourceCodeEnd":271,"githubUrl":"https://github.com/PrefectHQ/fastmcp/blob/1f021142978e0861cd910c8df4e8074bc7cf3978/fastmcp_slim/fastmcp/server/providers/aggregate.py#L235-L271","documentation":"When multiple providers aggregate the same app more than once, several tool components can share the identical tool hash. get_tool_by_hash cannot route a call to a single tool in that case, so it raises ToolError naming the tool, the number of matching components, and the colliding hash.","triggerScenarios":"Calling get_tool_by_hash(tool_name, tool_hash) when the same underlying app was composed/registered into the aggregation more than once, producing len(matches) > 1.","commonSituations":"Mounting the same sub-app under multiple paths without deduplication; accidental double registration during refactor; composite providers including an app already included directly.","solutions":["Remove the duplicate composition so each app is aggregated once","Give the duplicated app distinct identities/names per registration","Catch ToolError and disambiguate by provider path if intentional multiplexing is needed"],"exampleFix":"// before\naggregate.include(app)\naggregate.include(app)  # duplicate -> ambiguous hash\n\n// after\naggregate.include(app, name='app-a')\naggregate.include(app, name='app-b')  # or include only once","handlingStrategy":"try-catch","validationCode":"tools = await client.list_tools()\nnames = [t.name for t in tools]\nif len(names) != len(set(names)):\n    dupes = {n for n in names if names.count(n) > 1}\n    raise RuntimeError(f'Duplicate tool identities from repeated app composition: {dupes}')","typeGuard":null,"tryCatchPattern":"try:\n    tool = await aggregate.get_tool_by_hash(tool_name, tool_hash)\nexcept ToolError as e:\n    if 'Ambiguous app tool' in str(e):\n        tool = await resolve_tool_by_provider_path(tool_name)  # disambiguate\n    else:\n        raise","preventionTips":["Ensure each app is composed into an aggregate exactly once","Use distinct names/namespaces when intentionally including an app multiple times","Add a startup assertion that tool hashes are unique across the aggregate"],"tags":["tools","aggregation","ambiguity","providers"],"backgroundTag":"ambiguous-component-identity","analyzedSha":"1f021142978e0861cd910c8df4e8074bc7cf3978","analyzedAt":"2026-08-29T14:31:16.082Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}