crewAIInc/crewAI · error · MergeAgentHandlerToolError

Failed to load Tool Pack: {e!s}

Error message

Failed to load Tool Pack: {e!s}

What it means

Catch-all in the Tool Pack loader: after filtering and constructing MergeAgentHandlerTool instances for each discovered tool, any non-MergeAgentHandlerToolError exception is wrapped as 'Failed to load Tool Pack: ...' with the cause chained. This guards the loop that maps tools/list results into tool instances, so failures usually come from unexpected tool metadata shapes or constructor validation.

Source

Thrown at lib/crewai-tools/src/crewai_tools/tools/merge_agent_handler_tool/merge_agent_handler_tool.py:348

                if not tool_name:
                    continue

                tool = cls.from_tool_name(
                    tool_name=tool_name,
                    tool_pack_id=tool_pack_id,
                    registered_user_id=registered_user_id,
                    base_url=base_url,
                    **kwargs,
                )
                tools.append(tool)

            return tools

        except MergeAgentHandlerToolError:
            raise
        except Exception as e:
            logger.error(f"Failed to create tools from Tool Pack: {e!s}")
            raise MergeAgentHandlerToolError(f"Failed to load Tool Pack: {e!s}") from e

View on GitHub (pinned to 754d7323be)

Solutions

  1. Read e.__cause__ / the 'Failed to create tools from Tool Pack' log line to identify the offending tool
  2. Load without the tool_names filter to see whether one specific tool breaks the batch, then select the ones you need
  3. Retry with names copied verbatim from tools/list output (case-sensitive)
  4. If one tool's missing inputSchema is the cause, exclude it and construct that tool manually

Example fix

# before
TOOLS = MergeAgentHandlerTool.from_tool_name("a", PID, UID, tool_names=["A", "B"])
# Failed to load Tool Pack: KeyError ...

# after
TOOLS = MergeAgentHandlerTool.from_tool_name("a", PID, UID)  # load all
wanted = {t.tool_name for t in TOOLS}
assert {"A", "B"} <= wanted, f"available: {sorted(wanted)}"
Defensive patterns

Strategy: fallback

Validate before calling

def pack_tools_are_wellformed(tools_payload: list[dict]) -> bool:
    return all(t.get("name") for t in tools_payload)

Try / catch

try:
    TOOLS = MergeAgentHandlerTool.from_tool_name(name, PID, UID)
except MergeAgentHandlerToolError as e:
    if "Failed to load Tool Pack" in str(e):
        TOOLS = MergeAgentHandlerTool.from_tool_name(name, PID, UID)  # no filter, isolate bad tool
    raise

Prevention

When it happens

Trigger: A tool in the pack has no 'name' or missing fields the constructor needs (e.g. building args_schema from a tool without inputSchema); tool_names filter containing names causing downstream KeyErrors; pydantic validation rejecting a field during cls(...) construction.

Common situations: A pack containing tools with unusual metadata (function tools with no schema); stale pack version whose entries changed shape; requesting tool_names that mismatch casing.

Related errors


AI-assisted analysis of crewAIInc/crewAI@754d7323be (2026-08-15). Data as JSON: /api/errors/e5d2123c35791112. Report an issue: GitHub.