{"record":{"id":"d03c3dfdf51a1ba1","repo":"deepset-ai/haystack","slug":"searchabletoolset-does-not-support-adding-new-tool","errorCode":null,"errorMessage":"SearchableToolset does not support adding new tools after initialization.","messagePattern":"SearchableToolset does not support adding new tools after initialization\\.","errorType":"exception","errorClass":"NotImplementedError","httpStatus":null,"severity":"error","filePath":"haystack/tools/searchable_toolset.py","lineNumber":146,"sourceCode":"        self._discovered_tools: dict[str, Tool] = {}\n        self._bootstrap_tool: Tool | None = None\n        self._document_store: InMemoryDocumentStore | None = None\n        self._passthrough: bool | None = None\n\n        # Optional per-run name filter, set on the copies returned by spawn(). When set, iteration only\n        # yields tools whose name is in this set, and search is scoped to it. None means no filtering.\n        self._selected_tool_names: set[str] | None = None\n\n        # Initialize parent with empty tools list - we manage tools dynamically\n        super().__init__(tools=[])\n\n    def __add__(self, other: Tool | Toolset | list[Tool]) -> \"Toolset\":\n        \"\"\"Concatenation is not supported for SearchableToolset.\"\"\"\n        raise NotImplementedError(\"SearchableToolset does not support concatenation.\")\n\n    def add(self, tool: Tool | Toolset) -> None:\n        \"\"\"Adding new tools after initialization is not supported for SearchableToolset.\"\"\"\n        raise NotImplementedError(\"SearchableToolset does not support adding new tools after initialization.\")\n\n    def warm_up(self) -> None:\n        \"\"\"\n        Prepare the toolset for use.\n\n        Warms up the catalog (so lazy toolsets like MCPToolset can connect) and flattens it. Above the passthrough\n        threshold, it also indexes the catalog and creates the search_tools bootstrap tool.\n\n        This method is idempotent: it only warms up the toolset the first time it is called.\n\n        :raises ValueError: If the flattened catalog contains tools with duplicate names.\n        \"\"\"\n        if self._passthrough is not None:\n            return\n\n        # Warm up the catalog first (triggers lazy connections like MCPToolset), then flatten — lazy toolsets will\n        # have their real tools available.\n        warm_up_tools(self._raw_catalog)","sourceCodeStart":128,"sourceCodeEnd":164,"githubUrl":"https://github.com/deepset-ai/haystack/blob/e318778c9bf60a1963e3b5f451359655dd696c30/haystack/tools/searchable_toolset.py#L128-L164","documentation":"SearchableToolset.add() is intentionally disabled: the tool catalog is fixed at construction (plus warm_up-time flattening), so adding tools after initialization is not supported and raises NotImplementedError.","triggerScenarios":"searchable_toolset.add(new_tool) after construction, often in agent setup code that incrementally registers tools.","commonSituations":"Code that dynamically registers tools into a toolset post-init; migrating from regular Toolset (where add works) to SearchableToolset without updating setup logic.","solutions":["Pass all tools up front via SearchableToolset(catalog=[...]) including the tool you intended to add","Rebuild the toolset with the expanded catalog instead of mutating it","Use a plain Toolset if post-init mutation is required"],"exampleFix":"// before\nts = SearchableToolset(catalog=tools)\nts.add(new_tool)\n\n// after\nts = SearchableToolset(catalog=[*tools, new_tool])","handlingStrategy":"fallback","validationCode":"def register_tool(toolset, tool):\n    from haystack.tools import SearchableToolset\n    if isinstance(toolset, SearchableToolset):\n        raise TypeError(\"Rebuild SearchableToolset with the tool in catalog instead of add()\")\n    toolset.add(tool)","typeGuard":"def is_mutable_toolset(toolset) -> bool:\n    from haystack.tools import SearchableToolset\n    return not isinstance(toolset, SearchableToolset)","tryCatchPattern":"try:\n    toolset.add(new_tool)\nexcept NotImplementedError:\n    toolset = SearchableToolset(catalog=[*current_catalog, new_tool])","preventionTips":["Collect all tools before constructing a SearchableToolset","Use plain Toolset when dynamic registration is a requirement","Wrap tool registration behind a helper that rebuilds searchable toolsets"],"tags":["not-implemented","toolset","api-misuse"],"backgroundTag":"unsupported-operation","analyzedSha":"e318778c9bf60a1963e3b5f451359655dd696c30","analyzedAt":"2026-08-30T11:45:20.711Z","schemaVersion":2},"datasetVersion":"2026-08-30T13:17:10.514Z"}