zylon-ai/private-gpt · error · ToolNameConflictError

TOOL_NAME_CONFLICT

TOOL_NAME_CONFLICT

Error message

Tool name conflict: name='{tool.name}', layer_a='{existing}', layer_b='{layer.source}'

What it means

Thrown by ContextStackBuilder while validating global tool-name uniqueness. It walks every layer whose type is LayerType.TOOL_DEFINITIONS (an instance of ToolDefinitionsLayer) and records the first layer.source for each non-None tool.name; a second layer defining the same name raises ToolNameConflictError with both layer sources. Tools with name=None are skipped, and only the first owner is reported per name.

Source

Thrown at private_gpt/components/context/services/context_stack_builder.py:98

    def build(self) -> ContextStack:
        """Build an immutable stack after conflict checks."""
        self.validate_tool_name_uniqueness()
        return ContextStack(layers=list(self.layers))

    def validate_tool_name_uniqueness(self) -> None:
        """Validate global tool uniqueness across tool-definition layers."""
        seen: dict[str, str] = {}
        for layer in self.layers:
            if layer.type is not LayerType.TOOL_DEFINITIONS:
                continue
            if not isinstance(layer, ToolDefinitionsLayer):
                continue
            for tool in layer.tools:
                if tool.name is None:
                    continue
                existing = seen.get(tool.name)
                if existing is not None:
                    raise ToolNameConflictError(
                        "Tool name conflict: "
                        f"name='{tool.name}', "
                        f"layer_a='{existing}', layer_b='{layer.source}'"
                    )
                seen[tool.name] = layer.source

View on GitHub (pinned to 4a030776a3)

Solutions

  1. Find the two layers named in the message (layer_a / layer_b) and remove or rename the duplicated tool in one of them
  2. If both copies are the same tool set, drop the redundant ToolDefinitionsLayer instead of passing it twice
  3. Rename one MCP server's tool via its own tool-name prefix/alias configuration
  4. Rebuild the stack incrementally (add one tool layer at a time) to identify which layer introduces the conflict

Example fix

# before
stack = builder.build([
    tool_layer_from_server_a,  # defines 'search'
    tool_layer_from_server_b,  # also defines 'search' -> conflict
])

# after
stack = builder.build([
    tool_layer_from_server_a,
    rename_tools(tool_layer_from_server_b, prefix='b_'),
])
Defensive patterns

Strategy: validation

Validate before calling

def find_tool_conflicts(layers) -> dict[str, tuple[str, str]]:
    seen, conflicts = {}, {}
    for layer in layers:
        if getattr(layer, 'type', None).__class__ and layer.type is not None and str(layer.type).endswith('TOOL_DEFINITIONS'):
            for tool in getattr(layer, 'tools', []):
                if tool.name and tool.name in seen and seen[tool.name] != layer.source:
                    conflicts[tool.name] = (seen[tool.name], layer.source)
                elif tool.name:
                    seen[tool.name] = layer.source
    return conflicts

conflicts = find_tool_conflicts(builder.layers)
assert not conflicts, conflicts

Try / catch

try:
    stack = builder.build(layers)
except ToolNameConflictError as e:
    # message names both conflicting layer sources; drop/rename and rebuild
    raise HTTPException(400, str(e))

Prevention

When it happens

Trigger: Building a context stack that contains two ToolDefinitionsLayers whose tool lists both contain a tool with the same name (e.g. MCP servers exposing identically named tools, or the same tool set attached at two context levels). Triggered during stack construction/validation, not at tool invocation time.

Common situations: Connecting two MCP servers that both expose 'search' or 'read_file'; loading the same tool catalog twice (global layer + request-level layer); merging contexts from different providers that use generic tool names; upgrading a dependency that renames a built-in tool to collide with your custom tool.

Related errors


AI-assisted analysis of zylon-ai/private-gpt@4a030776a3 (2026-08-15). Data as JSON: /api/errors/ab644acd3b1f2b37. Report an issue: GitHub.