microsoft/aspire · error · InvalidOperationException

Toolbox ' ' contains duplicate tool names: .

Error message

Toolbox '{name}' contains duplicate tool names: {string.Join(", ", duplicateToolNames)}.

What it means

Thrown by FoundryToolboxReconciler.Create when two or more tool definitions in the collection share the same Name (compared with StringComparer.Ordinal). Tool names must be unique within a Toolbox because they become the identifiers the MCP clients invoke; duplicates would be ambiguous. The message lists the offending names.

Solutions

  1. Rename one of the duplicate tools so every tool name in the Toolbox is unique.
  2. If tools come from multiple MCP servers with colliding names, prefix names with the server label or scope.
  3. Deduplicate before calling Create (e.g. DistinctBy(t => t.Name, StringComparer.Ordinal)) and log dropped duplicates.

Example fix

// before
builder.WithMcpTool("search", "https://a.example.com/mcp");
builder.WithMcpTool("search", "https://b.example.com/mcp");
// after
builder.WithMcpTool("a-search", "https://a.example.com/mcp");
builder.WithMcpTool("b-search", "https://b.example.com/mcp");
Defensive patterns

Strategy: validation

Validate before calling

var dupes = tools.GroupBy(t => t.Name, StringComparer.Ordinal).Where(g => g.Count() > 1).Select(g => g.Key).ToArray();
if (dupes.Length > 0)
{
    throw new InvalidOperationException($"Duplicate tool names before Toolbox creation: {string.Join(", ", dupes)}");
}

Type guard

static bool HasUniqueToolNames(IEnumerable<FoundryToolDefinition> tools) =>
    tools.Select(t => t.Name).Distinct(StringComparer.Ordinal).Count() == tools.Count();

Try / catch

try
{
    var toolbox = FoundryToolboxReconciler.Create(name, description, tools, metadata);
}
catch (InvalidOperationException ex) when (ex.Message.Contains("duplicate tool names"))
{
    logger.LogError(ex, "Toolbox {Name} has duplicate tool names; rename one of the registrations.", name);
    throw;
}

Prevention

When it happens

Trigger: Calling Create with a tools collection containing two entries whose Name properties are identical — e.g. the same WithMcpTool name used twice, or tools aggregated from multiple sources that both register a tool named 'search'.

Common situations: Merging tool lists from config plus code where a name collides; loop that adds the same tool per-resource without suffixing names; copy-paste duplication in the app model; two MCP servers both exposing a tool with the same name added under one Toolbox.

Understand the failure class

Background: Conflicting config options: "cannot be used together" — configuration validation errors across open-source libraries — this error's family across 162 libraries.

Related errors


AI-assisted analysis of microsoft/aspire@25830f84bd (2026-09-16). Data as JSON: /api/errors/142619208f18a395. Report an issue: GitHub.

Appendix: source

Thrown at src/Aspire.Hosting.Foundry/Toolbox/FoundryToolboxReconciler.cs:76

        ArgumentException.ThrowIfNullOrWhiteSpace(description);
        ArgumentNullException.ThrowIfNull(tools);
        ArgumentNullException.ThrowIfNull(metadata);

        if (tools.Count == 0)
        {
            throw new InvalidOperationException($"Toolbox '{name}' must contain at least one tool.");
        }

        var duplicateToolNames = tools
            .GroupBy(tool => tool.Name, StringComparer.Ordinal)
            .Where(group => group.Count() > 1)
            .Select(group => group.Key)
            .Order(StringComparer.Ordinal)
            .ToArray();

        if (duplicateToolNames.Length > 0)
        {
            throw new InvalidOperationException(
                $"Toolbox '{name}' contains duplicate tool names: {string.Join(", ", duplicateToolNames)}.");
        }

        var duplicateMcpServerLabels = tools
            .Where(tool => tool.McpServerLabel is not null)
            .GroupBy(tool => tool.McpServerLabel!, StringComparer.Ordinal)
            .Where(group => group.Count() > 1)
            .Select(group => group.Key)
            .Order(StringComparer.Ordinal)
            .ToArray();
        if (duplicateMcpServerLabels.Length > 0)
        {
            throw new InvalidOperationException(
                $"Toolbox '{name}' contains duplicate MCP server labels: {string.Join(", ", duplicateMcpServerLabels)}.");
        }

        var maximumUserMetadataEntries = MaximumMetadataEntries - s_reservedMetadataKeys.Length;
        if (metadata.Count > maximumUserMetadataEntries)

View on GitHub (pinned to 25830f84bd)