{"record":{"id":"c1915884727e13f2","repo":"deepset-ai/haystack","slug":"searchabletoolset-does-not-support-concatenation","errorCode":null,"errorMessage":"SearchableToolset does not support concatenation.","messagePattern":"SearchableToolset does not support concatenation\\.","errorType":"exception","errorClass":"NotImplementedError","httpStatus":null,"severity":"error","filePath":"haystack/tools/searchable_toolset.py","lineNumber":142,"sourceCode":"        self._search_tool_description = search_tool_description\n        self._search_tool_parameters_description = search_tool_parameters_description\n\n        # Runtime state (initialized in warm_up)\n        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","sourceCodeStart":124,"sourceCodeEnd":160,"githubUrl":"https://github.com/deepset-ai/haystack/blob/e318778c9bf60a1963e3b5f451359655dd696c30/haystack/tools/searchable_toolset.py#L124-L160","documentation":"SearchableToolset manages its tool catalog dynamically (search/select), so the Toolset '+' concatenation operator is intentionally unsupported. Using searchable_toolset + other_tool raises NotImplementedError rather than silently producing a broken set.","triggerScenarios":"combined = searchable_toolset + another_tool or searchable + [t1, t2]; also occurrences where code sums a mixed list of toolsets with sum()/reduce.","commonSituations":"Code that concatenates ordinary Toolsets being reused with a SearchableToolset; combining agent tool lists with + idiomatically.","solutions":["Include the extra tools in the catalog list at construction: SearchableToolset(catalog=[...tools, extra_tool])","Use a plain Toolset if you need + concatenation and don't need search semantics","Build a combined list first and pass it once to SearchableToolset(catalog=combined)"],"exampleFix":"// before\nts = searchable_toolset + extra_tool\n\n// after\nts = SearchableToolset(catalog=list(base_catalog) + [extra_tool])","handlingStrategy":"fallback","validationCode":"def combine_toolsets(a, b):\n    from haystack.tools import SearchableToolset, Toolset\n    if isinstance(a, SearchableToolset) or isinstance(b, SearchableToolset):\n        return SearchableToolset(catalog=[a, b])\n    return a + b","typeGuard":"def supports_concat(toolset) -> bool:\n    return not isinstance(toolset, SearchableToolset)","tryCatchPattern":"try:\n    combined = searchable + extra\nexcept NotImplementedError:\n    combined = SearchableToolset(catalog=[searchable, extra])","preventionTips":["Don't use + with SearchableToolset; compose via the catalog argument","Check the toolset class docs for which mutation/combination ops are supported","Encapsulate toolset combination in one helper that handles both kinds"],"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"}