microsoft/aspire · error · DistributedApplicationException

Java application ' ' cannot be published because its…

Error message

Java application '{resource.Name}' cannot be published because its wrapper path '{relative}' contains whitespace, which a Dockerfile COPY instruction cannot express. Move the wrapper to a path without spaces.

What it means

The wrapper's path relative to the build context contains whitespace. A Dockerfile COPY instruction separates its arguments by whitespace and this generator does not emit a quoted form, so a spaced path would copy two wrong paths. Aspire rejects it at publish time with a clear message instead of an opaque 'no such file or directory' inside the Docker build.

Solutions

  1. Move the wrapper (and ideally the whole app) to a path without spaces within the build context.
  2. Rename the containing directory to remove spaces (e.g. 'MyProject' instead of 'My Project').
  3. Restructure so the build context directory itself and its path to the wrapper contain no whitespace.

Example fix

// before
builder.AddJavaApp("api", "My Project/Api"); // wrapper at 'My Project/Api/mvnw'
// after
builder.AddJavaApp("api", "MyProject/Api"); // rename folder to remove the space
Defensive patterns

Strategy: validation

Validate before calling

var relative = Path.GetRelativePath(context, wrapper);
if (relative.Any(char.IsWhiteSpace))
    throw new Exception($"Wrapper path '{relative}' must not contain whitespace");

Try / catch

try { /* publish */ }
catch (DistributedApplicationException ex) when (ex.Message.Contains("contains whitespace"))
{ /* relocate wrapper/app to a space-free path, then republish */ }

Prevention

When it happens

Trigger: Publishing a Java app whose wrapper resolves to a relative path containing a space, e.g. the app lives in 'My Project/Api' or WithWrapperPath points into a folder like 'build tools/mvnw'.

Common situations: Solution folders with spaces ('Visual Studio Projects', 'My App'); cloning repos into directories with spaces; wrapper placed under a directory named with spaces inside the context.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


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

Appendix: source

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

                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 " +
                    "express. Move the wrapper to a path without spaces.");
            }

            return relative;
        }

        internal static (JavaBuildTool Tool, string[] Args) ResolveToolAndArgs(JavaAppResource resource, string appDirectory)
        {
            var (tool, args) = ResolveConfiguredToolAndArgs(resource, appDirectory);

            return (tool, WithoutGradleDaemon(tool, args));
        }

        /// <summary>
        /// Adds <c>--no-daemon</c> to a Gradle invocation that does not already carry it.
        /// </summary>

View on GitHub (pinned to 25830f84bd)