microsoft/aspire · error · DistributedApplicationException

Java application ' ' cannot be published because its…

Error message

Java application '{resource.Name}' cannot be published because its wrapper '{relative}' is a Windows batch script and the container build stage is Linux. No '{posixSibling}' was found next to it. Generate the wrapper with {JavaHostingExtensions.GenerateWrapperCommand(tool)} so both scripts are present.

What it means

The publish-time container build runs on Linux, but the only wrapper found is a Windows batch script (.cmd/.bat) with no extension-less POSIX sibling next to it. Aspire rejects the publish because the Linux Docker build could not execute the batch script. Generating the wrapper with the documented command produces both scripts so the image builds on either platform.

Solutions

  1. Generate the wrapper with JavaHostingExtensions.GenerateWrapperCommand(tool) (mvn wrapper:wrapper / gradle wrapper) so both the POSIX and Windows scripts exist.
  2. Add/commit the extension-less POSIX wrapper (mvnw or gradlew) next to the .cmd/.bat file in the build context.
  3. Point WithWrapperPath at an existing POSIX wrapper inside the app directory.

Example fix

// before
.WithWrapperPath("mvnw.cmd"); // only the .cmd exists
// after
// regenerate so mvnw + mvnw.cmd both exist
.WithWrapperPath("mvnw");
Defensive patterns

Strategy: validation

Validate before calling

var wrapper = "mvnw.cmd";
var posix = Path.ChangeExtension(wrapper, null);
if (wrapper.EndsWith(".cmd") || wrapper.EndsWith(".bat"))
{
    if (!File.Exists(posix))
        Console.WriteLine($"Missing POSIX wrapper '{posix}' for Linux container builds");
}

Try / catch

try { /* publish */ }
catch (DistributedApplicationException ex) when (ex.Message.Contains("Windows batch script"))
{ /* generate both wrapper scripts, then republish */ }

Prevention

When it happens

Trigger: Publishing a Java app whose resolved wrapper ends in .cmd or .bat (e.g. configured WithWrapperPath("mvnw.cmd") on a Windows dev machine) and no 'mvnw'/'gradlew' file exists in the same directory of the build context.

Common situations: Developing on Windows and only the .cmd wrapper was generated or committed; .gitignore or the team excluding the extension-less script; copying wrapper scripts from a Windows-only checkout into the repo.

Understand the failure class

Background: "unsupported platform" / "not supported on this platform" errors: what they mean and how to fix them — this error's family across 47 libraries.

Related errors


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

Appendix: source

Thrown at src/Aspire.Hosting.Java/JavaDockerfileGenerator.cs:1081

                    $"Java application '{resource.Name}' cannot be published because there is no " +
                    $"{defaultWrapperName} in '{appDirectory}'. Aspire builds the image with the project's " +
                    $"own wrapper so the container uses the tool version the repository pins. Generate one " +
                    $"with {JavaHostingExtensions.GenerateWrapperCommand(tool)}, or point at an existing " +
                    "wrapper with WithWrapperPath.");
            }

            // The build stage is Linux, so a Windows batch wrapper cannot run there even though it is
            // the right choice on the developer's machine. Maven and Gradle ship the POSIX script
            // alongside the batch one under the same base name, so prefer that sibling and only fail
            // when it is genuinely absent.
            // https://maven.apache.org/wrapper/ and https://docs.gradle.org/current/userguide/gradle_wrapper.html
            if (Path.GetExtension(relative) is ".cmd" or ".bat")
            {
                var posixSibling = relative[..^Path.GetExtension(relative).Length];

                if (!File.Exists(Path.Combine(appDirectory, posixSibling.Replace('/', Path.DirectorySeparatorChar))))
                {
                    throw new DistributedApplicationException(
                        $"Java application '{resource.Name}' cannot be published because its wrapper " +
                        $"'{relative}' is a Windows batch script and the container build stage is Linux. " +
                        $"No '{posixSibling}' was found next to it. Generate the wrapper with " +
                        $"{JavaHostingExtensions.GenerateWrapperCommand(tool)} so both scripts are present.");
                }

                relative = posixSibling;
            }

            // A Dockerfile COPY takes its arguments separated by whitespace and has no quoted form here,
            // so a wrapper path containing whitespace would copy two nonexistent paths instead of one real
            // one. Rejecting it names the problem, rather than failing later inside the build with "no such
            // file or directory" for a path the author never wrote.
            if (relative.Any(char.IsWhiteSpace))
            {
                throw new DistributedApplicationException(
                    $"Java application '{resource.Name}' cannot be published because its wrapper path " +
                    $"'{relative}' contains whitespace, which a Dockerfile COPY instruction cannot " +

View on GitHub (pinned to 25830f84bd)