microsoft/aspire · error · InvalidOperationException
Toolbox ' ' must contain at least one tool.
Error message
Toolbox '{name}' must contain at least one tool. What it means
Thrown by FoundryToolboxReconciler.Create when the tools collection is empty (after null checks). A Toolbox must declare at least one tool definition; creating one with zero tools would produce a useless remote Toolbox, so it is rejected eagerly as an invalid operation.
Solutions
- Add at least one tool definition (WithMcpTool, AddAiSearchTool, or a Bing grounding tool) before creating the Toolbox.
- If tools come from configuration, validate the list is non-empty before calling Create and surface a clear startup error.
- If conditional tool registration is intentional, guard the Toolbox creation itself behind the same condition.
Example fix
// before
var tools = config.EnabledTools.Select(...).ToArray(); // empty when nothing enabled
var toolbox = FoundryToolboxReconciler.Create("tb", desc, tools, metadata);
// after
if (tools.Count == 0) throw new InvalidOperationException("No tools enabled in configuration; cannot create Toolbox.");
var toolbox = FoundryToolboxReconciler.Create("tb", desc, tools, metadata); Defensive patterns
Strategy: validation
Validate before calling
if (tools is not { Count: > 0 })
{
throw new InvalidOperationException("At least one tool must be registered before creating a Foundry Toolbox.");
} Type guard
static bool HasTools(IReadOnlyList<FoundryToolDefinition> tools) => tools.Count > 0;
Try / catch
try
{
var toolbox = FoundryToolboxReconciler.Create(name, description, tools, metadata);
}
catch (InvalidOperationException ex) when (ex.Message.Contains("must contain at least one tool"))
{
logger.LogError(ex, "Toolbox {Name} was created with no tools.", name);
throw;
} Prevention
- Assert tool registrations in app-model unit tests so an empty toolbox fails at test time.
- Fail fast at config load when conditional tool registration yields an empty list.
- Pair every conditional tool-removal with a guard on Toolbox creation.
When it happens
Trigger: Calling Create (via AddFoundryToolbox-style builders) with an empty tools list — e.g. conditionally-added tools were all skipped, or the caller forgot to add any With*Tool calls.
Common situations: Building the tool list from configuration where all entries were filtered out; refactoring that removed tool registrations; feature flags disabling every tool at runtime.
Understand the failure class
Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.
Related errors
- Endpoint must be a string, endpoint reference, or reference…
- The MCP endpoint must be a Foundry-reachable absolute HTTPS…
- Toolbox ' ' contains duplicate tool names: .
- -32602
- A discovered Toolbox tool did not have a name.
AI-assisted analysis of microsoft/aspire@25830f84bd (2026-09-16).
Data as JSON: /api/errors/1cadc4ab00b244da.
Report an issue: GitHub.
Appendix: source
Thrown at src/Aspire.Hosting.Foundry/Toolbox/FoundryToolboxReconciler.cs:64
public IReadOnlyDictionary<string, string> Metadata { get; }
public string ConfigurationHash { get; }
public static FoundryToolboxDeploymentDefinition Create(
string name,
string description,
IReadOnlyList<ResolvedFoundryToolboxTool> tools,
IReadOnlyDictionary<string, string> metadata)
{
ArgumentException.ThrowIfNullOrEmpty(name);
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)View on GitHub (pinned to 25830f84bd)