microsoft/aspire · error · DistributedApplicationException

Java application ' ' cannot be published because the…

Error message

Java application '{resource.Name}' cannot be published because the wrapper configured with WithWrapperPath was not found at '{resolvedWrapperPath}'.

What it means

During publish, the wrapper path explicitly configured via WithWrapperPath does not exist on disk. Aspire validates the configured wrapper before emitting the Dockerfile so the failure is named at publish time rather than surfacing as a Docker build error. It is thrown only when the wrapper was explicitly configured (WrapperAnnotation present), distinguishing user error from the missing-default-wrapper case.

Solutions

  1. Correct the path passed to WithWrapperPath so it points at the existing wrapper script.
  2. Generate the wrapper with the documented command (e.g. mvn wrapper:wrapper or gradle wrapper) inside the app directory.
  3. Verify the file exists on disk at the exact resolved path before publishing.

Example fix

// before
.WithWrapperPath("mvnw.sh") // file is actually named 'mvnw'
// after
.WithWrapperPath("mvnw");
Defensive patterns

Strategy: validation

Validate before calling

var wrapper = "src/Api/mvnw";
if (!File.Exists(wrapper))
    throw new FileNotFoundException($"Configured wrapper missing: {wrapper}");

Try / catch

try { /* publish */ }
catch (DistributedApplicationException ex) when (ex.Message.Contains("WithWrapperPath was not found"))
{ /* fix or generate the wrapper, then republish */ }

Prevention

When it happens

Trigger: Publishing an AddJavaApp resource after calling WithWrapperPath("<path>") where that file does not exist at the resolved path (typo, wrong relative base, file deleted, or the wrapper was never generated).

Common situations: Typo in the wrapper filename; passing a directory instead of the script; wrapper generated on another machine/OS and not committed; repo cloned without the wrapper because .gitignore excluded it; resolving relative to a different current directory than expected.

Understand the failure class

Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.

Related errors


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

Appendix: source

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

            // script that the build stage cannot execute.
            var resolvedWrapperPath = JavaBuildToolResolver.ResolveWrapperPath(resource, tool, isWindows: false);
            var isConfigured = resource.HasAnnotationOfType<WrapperAnnotation>();
            var relative = Path.GetRelativePath(appDirectory, resolvedWrapperPath).Replace('\\', '/');

            if (relative.StartsWith("../", StringComparison.Ordinal) || IsPathRootedOnAnyPlatform(relative))
            {
                throw new DistributedApplicationException(
                    $"Java application '{resource.Name}' cannot be published because its wrapper " +
                    $"'{resolvedWrapperPath}' is outside the build context '{appDirectory}'. " +
                    "Move the wrapper into the application directory, or set the build context to a " +
                    "directory that contains both.");
            }

            if (!File.Exists(resolvedWrapperPath))
            {
                if (isConfigured)
                {
                    throw new DistributedApplicationException(
                        $"Java application '{resource.Name}' cannot be published because the wrapper " +
                        $"configured with WithWrapperPath was not found at '{resolvedWrapperPath}'.");
                }

                var defaultWrapperName = JavaBuildToolResolver.GetDefaultWrapperName(tool, isWindows: false);
                throw new DistributedApplicationException(
                    $"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

View on GitHub (pinned to 25830f84bd)