microsoft/aspire · error · ArgumentOutOfRangeException
ArgumentOutOfRangeException: Specified argument was out of…
Error message
ArgumentOutOfRangeException: Specified argument was out of range of valid values. (Parameter 'tool')
What it means
GenerateWrapperCommand maps a JavaBuildTool enum value to the wrapper-generation command string. The library throws ArgumentOutOfRangeException when the tool value is not Maven or Gradle, i.e. an undefined or future enum member reached this switch, so it fails fast instead of producing a broken command.
Solutions
- Pass only JavaBuildTool.Maven or JavaBuildTool.Gradle to the hosting API.
- Validate the enum with Enum.IsDefined before casting from int/string config values.
- Rebuild and redeploy all assemblies together so the enum and its consumers match versions.
- If adding a new JavaBuildTool member, update GenerateWrapperCommand's switch expression.
Example fix
// before
var tool = (JavaBuildTool)42;
builder.AddJavaApp("svc", ...
// after
var raw = 42;
var tool = Enum.IsDefined(typeof(JavaBuildTool), raw) ? (JavaBuildTool)raw : throw new ArgumentException($"Unknown build tool: {raw}"); Defensive patterns
Strategy: validation
Validate before calling
if (!Enum.IsDefined(typeof(JavaBuildTool), tool)) throw new ArgumentException($"Unsupported JavaBuildTool: {tool}"); Type guard
static bool IsValidJavaBuildTool(JavaBuildTool tool) => Enum.IsDefined(tool);
Try / catch
try { builder.AddJavaApp(...); } catch (ArgumentOutOfRangeException ex) when (ex.ParamName == "tool") { /* map to user-facing config error */ } Prevention
- Never cast raw ints/strings to JavaBuildTool without Enum.IsDefined/Enum.TryParse
- Keep all NuGet package versions aligned when upgrading Aspire
- Use switch expressions with no discard arm so the compiler forces exhaustive handling
When it happens
Trigger: Calling an API that accepts a JavaBuildTool (e.g. AddJavaApp/Maven/Gradle wrapper generation paths) with a JavaBuildTool value other than Maven or Gradle, typically via an unsafe cast or a stale compiled assembly after the enum gained new members.
Common situations: Casting an int or string parsed from config into JavaBuildTool without validating it; running an old Aspire.Hosting.Java binary against newer code that added an enum member; typos in custom tooling that constructs the enum.
Understand the failure class
Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.
Related errors
- ArgumentOutOfRangeException: Specified argument was out of…
- ArgumentOutOfRangeException: Specified argument was out of…
- The inspect mode must be a defined DenoInspectMode value.
- The node_modules mode must be a defined…
- The permission kind must be a defined DenoPermissionKind…
AI-assisted analysis of microsoft/aspire@25830f84bd (2026-09-16).
Data as JSON: /api/errors/37314f5492b2eff0.
Report an issue: GitHub.
Appendix: source
Thrown at src/Aspire.Hosting.Java/JavaHostingExtensions.cs:1584
builder.WithAnnotation(new JavaWrapperValidationAnnotation(tool));
return builder.OnBeforeResourceStarted((resource, _, _) =>
{
ValidateWrapperExists(resource, tool);
return Task.CompletedTask;
});
}
/// <summary>
/// The command that adds a wrapper to an existing project, named in the error raised when one is missing.
/// </summary>
internal static string GenerateWrapperCommand(JavaBuildTool tool) => tool switch
{
// -N keeps the goal from recursing into the modules of a multi-module build, which would litter
// every module with a wrapper that only the root needs.
JavaBuildTool.Maven => "'mvn -N wrapper:wrapper'",
JavaBuildTool.Gradle => "'gradle wrapper'",
_ => throw new ArgumentOutOfRangeException(nameof(tool), tool, null)
};
/// <summary>
/// Appends <paramref name="values"/> to the <c>JAVA_TOOL_OPTIONS</c> environment variable, preserving
/// whatever is already there.
/// </summary>
/// <remarks>
/// The existing value may be any expression Aspire supports — a plain string, a
/// <see cref="ReferenceExpression"/>, a parameter, or an endpoint reference — so a non-string value is
/// folded into a new <see cref="ReferenceExpression"/> rather than being read as a string. An earlier
/// string-only implementation silently discarded non-string values.
/// </remarks>
private static void AppendJavaToolOptions(Dictionary<string, object> environmentVariables, string[] values)
{
var appended = string.Join(' ', values.Select(QuoteIfNeeded));
if (!environmentVariables.TryGetValue(JavaToolOptions, out var existing) || existing is null)
{View on GitHub (pinned to 25830f84bd)