{"record":{"id":"08666d07b36612b5","repo":"microsoft/aspire","slug":"java-application-resource-name-cannot-be-published-because-08666d","errorCode":null,"errorMessage":"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.","messagePattern":"Java application '(.+?)' cannot be published because its wrapper '(.+?)' is outside the build context '(.+?)'\\. Move the wrapper into the application directory, or set the build context to a directory that contains both\\.","errorType":"exception","errorClass":"DistributedApplicationException","httpStatus":null,"severity":"error","filePath":"src/Aspire.Hosting.Java/JavaDockerfileGenerator.cs","lineNumber":1045,"sourceCode":"        /// <para>\n        /// The wrapper also has to sit inside the build context, because only files under the context are\n        /// uploaded to the daemon and reachable by <c>COPY . .</c>. A wrapper outside it exists on the host\n        /// and not in the image, so the build would fail partway through with an opaque \"not found\".\n        /// </para>\n        /// </remarks>\n        /// <exception cref=\"DistributedApplicationException\">No wrapper is present, or the configured wrapper is outside the build context.</exception>\n        private static string ResolveWrapperForContext(JavaAppResource resource, string appDirectory, JavaBuildTool tool)\n        {\n            // Container builds execute on Linux even when publish runs on Windows. Passing that platform\n            // to the shared resolver keeps the naming rule identical to run mode without selecting a batch\n            // script that the build stage cannot execute.\n            var resolvedWrapperPath = JavaBuildToolResolver.ResolveWrapperPath(resource, tool, isWindows: false);\n            var isConfigured = resource.HasAnnotationOfType<WrapperAnnotation>();\n            var relative = Path.GetRelativePath(appDirectory, resolvedWrapperPath).Replace('\\\\', '/');\n\n            if (relative.StartsWith(\"../\", StringComparison.Ordinal) || IsPathRootedOnAnyPlatform(relative))\n            {\n                throw new DistributedApplicationException(\n                    $\"Java application '{resource.Name}' cannot be published because its wrapper \" +\n                    $\"'{resolvedWrapperPath}' is outside the build context '{appDirectory}'. \" +\n                    \"Move the wrapper into the application directory, or set the build context to a \" +\n                    \"directory that contains both.\");\n            }\n\n            if (!File.Exists(resolvedWrapperPath))\n            {\n                if (isConfigured)\n                {\n                    throw new DistributedApplicationException(\n                        $\"Java application '{resource.Name}' cannot be published because the wrapper \" +\n                        $\"configured with WithWrapperPath was not found at '{resolvedWrapperPath}'.\");\n                }\n\n                var defaultWrapperName = JavaBuildToolResolver.GetDefaultWrapperName(tool, isWindows: false);\n                throw new DistributedApplicationException(\n                    $\"Java application '{resource.Name}' cannot be published because there is no \" +","sourceCodeStart":1027,"sourceCodeEnd":1063,"githubUrl":"https://github.com/microsoft/aspire/blob/25830f84bd145686607ad00c057b3f84e2e51d43/src/Aspire.Hosting.Java/JavaDockerfileGenerator.cs#L1027-L1063","documentation":"Aspire's Java Dockerfile generator throws this when the resolved wrapper script (mvnw/gradlew) for a Java app resource resolves outside the Docker build context directory (appDirectory). The Dockerfile must COPY the wrapper from the build context, so a path escaping it (or an absolute path) cannot be expressed. This is a publish-time configuration validation to fail early instead of producing a broken image build.","triggerScenarios":"Calling aspire publish (or generating a Dockerfile) for an AddJavaApp resource whose wrapper — set via WithWrapperPath or the default lookup — resolves to a path outside the app's directory, e.g. '../mvnw' relative path or an absolute path on another root.","commonSituations":"Pointing WithWrapperPath at a shared wrapper in a parent or sibling repo directory; the app directory being a subfolder of the solution while the wrapper lives at the repo root; Windows absolute wrapper paths mixed with Linux context assumptions.","solutions":["Move the wrapper script (mvnw/gradlew) into the Java application directory used as the build context.","Change the build context (the directory passed to AddJavaApp) so it contains both the app sources and the wrapper.","Point WithWrapperPath at a wrapper that already exists inside the app directory."],"exampleFix":"// before\nbuilder.AddJavaApp(\"api\", \"src/Api\")\n    .WithWrapperPath(\"../mvnw\");\n// after\nbuilder.AddJavaApp(\"api\", \".\")\n    .WithWrapperPath(\"src/Api/mvnw\");","handlingStrategy":"validation","validationCode":"var wrapper = \"src/Api/mvnw\";\nvar context = \"src/Api\";\nvar rel = Path.GetRelativePath(context, wrapper);\nif (rel.StartsWith(\"../\") || Path.IsPathRooted(rel))\n    throw new Exception(\"Wrapper must be inside the build context\");","typeGuard":null,"tryCatchPattern":"try { /* publish */ }\ncatch (DistributedApplicationException ex) when (ex.Message.Contains(\"outside the build context\"))\n{ /* move wrapper or change context, then republish */ }","preventionTips":["Keep mvnw/gradlew committed inside the Java project directory","Never reference wrappers from parent or sibling directories","Pass the project root containing both sources and wrapper to AddJavaApp"],"tags":["java","dockerfile","publish","build-context"],"backgroundTag":"invalid-argument-value","analyzedSha":"25830f84bd145686607ad00c057b3f84e2e51d43","analyzedAt":"2026-09-16T11:10:06.193Z","contentChangedAt":"2026-09-16T11:10:06.193Z","schemaVersion":2},"datasetVersion":"2026-09-21T04:17:39.646Z"}