deepset-ai/haystack · warning · FutureWarning

Adding a Toolset to another Toolset is deprecated and will b

Error message

Adding a Toolset to another Toolset is deprecated and will be removed in Haystack 3.2.0. Pass Toolsets as a list wherever tools are accepted instead, e.g. Agent(tools=[toolset_a, toolset_b]).

What it means

Toolset.add(tool) in haystack/tools/toolset.py emits this FutureWarning when the object being added is itself a Toolset. Nesting one Toolset inside another via add() is deprecated in favor of passing toolsets as a flat list to any API that accepts tools (removed in Haystack 3.2.0).

Source

Thrown at haystack/tools/toolset.py:213

        Note: adding a Toolset flattens it into its individual tools, so this is only recommended
        for Toolsets that don't manage shared resources in their `warm_up()` (or `__init__`).
        For example, combining with an `MCPToolset`, which owns a shared connection, is not
        recommended: the connection's lifecycle would no longer be managed by the original
        Toolset.

        Adding a Toolset is deprecated and will be removed in Haystack 3.2.0: pass Toolsets as a
        list wherever tools are accepted instead, e.g. `Agent(tools=[toolset_a, toolset_b])`.

        :param tool: A Tool instance or another Toolset to add
        :raises ValueError: If adding the tool would result in duplicate tool names
        :raises TypeError: If the provided object is not a Tool or Toolset
        """
        if not isinstance(tool, (Tool, Toolset)):
            raise TypeError(f"Expected Tool or Toolset, got {type(tool).__name__}")

        if isinstance(tool, Toolset):
            warnings.warn(
                "Adding a Toolset to another Toolset is deprecated and will be removed in Haystack 3.2.0. "
                "Pass Toolsets as a list wherever tools are accepted instead, "
                "e.g. Agent(tools=[toolset_a, toolset_b]).",
                FutureWarning,
                stacklevel=2,
            )

        new_tools = [tool] if isinstance(tool, Tool) else list(tool)

        # Check for duplicates before adding
        _check_duplicate_tool_names(self.tools + new_tools)
        self.tools.extend(new_tools)

    def to_dict(self) -> dict[str, Any]:
        """
        Serialize the Toolset to a dictionary.

        :returns: A dictionary representation of the Toolset

View on GitHub (pinned to e318778c9b)

Solutions

  1. Stop calling .add() with a Toolset; pass toolsets directly as a list where tools are accepted, e.g. Agent(tools=[toolset_a, toolset_b])
  2. If a single flat collection is required, iterate and add individual Tools: for t in toolset_b: toolset_a.add(t)
  3. Combine with list concatenation of Toolsets: Toolset(toolsets=[toolset_a, toolset_b]) or use a plain list [toolset_a, toolset_b]
  4. Suppress with warnings.filterwarnings('ignore', category=FutureWarning, module='haystack') only as a temporary measure before Haystack 3.2.0

Example fix

# before
catalog = Toolset(tools=[])
catalog.add(toolset_a)
catalog.add(toolset_b)
agent = Agent(chat_generator=gen, tools=[catalog])
# after
agent = Agent(chat_generator=gen, tools=[toolset_a, toolset_b])
# or, if a flat Toolset is required:
for t in toolset_a:
    catalog.add(t)
for t in toolset_b:
    catalog.add(t)
Defensive patterns

Strategy: type-guard

Validate before calling

from haystack.tools import Tool, Toolset

def safe_add(target: Toolset, item) -> None:
    if isinstance(item, Toolset):
        raise ValueError("Pass toolsets as a list to consumers, not via .add()")
    if not isinstance(item, Tool):
        raise TypeError(f"Expected Tool, got {type(item).__name__}")
    target.add(item)

Type guard

from haystack.tools import Tool, Toolset

def is_tool(item) -> bool:
    return isinstance(item, Tool) and not isinstance(item, Toolset)

def is_toolset(item) -> bool:
    return isinstance(item, Toolset)

Try / catch

import warnings
from haystack.tools import Toolset

with warnings.catch_warnings(record=True) as caught:
    warnings.simplefilter("always", FutureWarning)
    target.add(maybe_toolset)
    if any(issubclass(w.category, FutureWarning) for w in caught):
        # a Toolset was passed; refactor to pass it as a list instead
        pass

Prevention

When it happens

Trigger: Calling toolset_a.add(toolset_b) where toolset_b is an instance of Toolset (or subclass); the TypeError check passes because Toolset is an allowed type, then the warning fires.

Common situations: Building a combined tool catalog by incrementally adding toolsets into a master Toolset; refactors where a variable that used to be a Tool became a Toolset; utility functions typed to accept Tool that now receive Toolset instances.

Related errors


AI-assisted analysis of deepset-ai/haystack@e318778c9b (2026-08-30). Data as JSON: /api/errors/4dab95fb68d699af. Report an issue: GitHub.