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

  1. Pass only JavaBuildTool.Maven or JavaBuildTool.Gradle to the hosting API.
  2. Validate the enum with Enum.IsDefined before casting from int/string config values.
  3. Rebuild and redeploy all assemblies together so the enum and its consumers match versions.
  4. 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

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


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)