deepset-ai/haystack · error · TypeError

{type(chat_generator).__name__} does not accept tools parame

Error message

{type(chat_generator).__name__} does not accept tools parameter in its run method. The Agent component requires a chat generator that supports tools when tools are provided.

What it means

warm_up builds a dict keyed by skill name; skill names must be unique across the store. This ValueError is raised when two skill files resolve to the same name — either both declare the same 'name' in frontmatter, or one's frontmatter name collides with another skill's directory name (used as fallback when 'name' is absent).

Source

Thrown at haystack/components/agents/agent.py:464

              Agent running by setting the `continue_run` control flag (`state.set("continue_run", True)`), usually
              alongside a message telling the model what to do next. "on_exit" hooks run when the Agent stops on an
              exit condition, but not when it stops because `max_agent_steps` is reached.
            - "after_run": Runs once per run, after the step loop has ended and before the Agent builds its return
              value — regardless of whether the run stopped on an exit condition or because `max_agent_steps` was
              reached (unlike "on_exit"). Mutations to the state (e.g. appending a final message) are reflected in
              the returned `messages` / `last_message` and `state_schema` outputs. Setting `continue_run` here has
              no effect.
        :raises TypeError: If the chat_generator does not support tools parameter in its run method.
        :raises ValueError: If any `user_prompt` variable overlaps with the `state_schema` or `run` method parameters,
            if a hook is registered under an unknown hook point, or if a hook is registered under a hook point it does
            not support (via its `allowed_hook_points`).
        """
        # --- Validation ---
        self._chat_generator_supports_tools: bool = "tools" in inspect.signature(chat_generator.run).parameters
        # We use an explicit None check for tools b/c testing for truthiness calls __len__, which for SearchableToolset
        # would iterate and prematurely warm it up at init.
        if tools is not None and not self._chat_generator_supports_tools:
            raise TypeError(
                f"{type(chat_generator).__name__} does not accept tools parameter in its run method. "
                "The Agent component requires a chat generator that supports tools when tools are provided."
            )

        if exit_conditions is None:
            exit_conditions = ["text"]

        if state_schema is not None:
            reserved_keys = _RUN_METADATA_STATE_KEYS.keys() | _INTERNAL_STATE_KEYS.keys()
            reserved_used = sorted(set(state_schema) & reserved_keys)
            if reserved_used:
                raise ValueError(
                    f"state_schema keys {reserved_used} are reserved for Agent internal state and "
                    f"cannot be redefined. Reserved keys: {sorted(reserved_keys)}."
                )
            _validate_schema(state_schema)
        _validate_prompt_message_blocks(user_prompt, system_prompt)
        if tool_concurrency_limit < 1:

View on GitHub (pinned to e318778c9b)

Solutions

  1. Rename the 'name' field in one of the colliding skills' frontmatter so each name is unique.
  2. If the collision comes from directory-name fallback, either set an explicit unique 'name' or rename the skill directory.
  3. Remove duplicate/copied skill directories or symlinks from skills_dir.

Example fix

// before (skills/backup/SKILL.md and skills/backup-v2/SKILL.md)
name: backup
// after (backup-v2/SKILL.md)
name: backup-v2
Defensive patterns

Strategy: validation

Validate before calling

import yaml
from pathlib import Path
from collections import Counter

def find_duplicate_skill_names(skills_dir: Path) -> list[str]:
    names = []
    for md in skills_dir.glob("**/*.md"):
        lines = md.read_text(encoding="utf-8").splitlines()
        if lines and lines[0].strip() == "---":
            closing = lines.index("---", 1)
            fm = yaml.safe_load("\n".join(lines[1:closing])) or {}
            names.append(fm.get("name", md.parent.name))
    return [n for n, c in Counter(names).items() if c > 1]

Try / catch

try:
    store.list_skills()
except ValueError as e:
    if "Duplicate skill name" in str(e):
        logger.error("Rename one of the colliding skills: %s", e)
    raise

Prevention

When it happens

Trigger: Two .md skill files in skills_dir declaring 'name: my-skill'; or skill dirs 'foo/' and 'bar/' where bar/SKILL.md declares 'name: foo'. Detected during warm_up via list_skills/load_skill.

Common situations: Copying a skill directory to iterate on it without changing the frontmatter 'name'; a nested directory plus a top-level skill sharing the frontmatter name; symlinks or duplicated skills checked into the repo twice.

Related errors


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