{"record":{"id":"6c43efc157c5ef7f","repo":"microsoft/aspire","slug":"java-application-resource-name-cannot-be-published-because-6c43ef","errorCode":null,"errorMessage":"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.","messagePattern":"Java application '(.+?)' cannot be published because its wrapper '(.+?)' is a Windows batch script and the container build stage is Linux\\. No '(.+?)' was found next to it\\. Generate the wrapper with (.+?) so both scripts are present\\.","errorType":"exception","errorClass":"DistributedApplicationException","httpStatus":null,"severity":"error","filePath":"src/Aspire.Hosting.Java/JavaDockerfileGenerator.cs","lineNumber":1081,"sourceCode":"                    $\"Java application '{resource.Name}' cannot be published because there is no \" +\n                    $\"{defaultWrapperName} in '{appDirectory}'. Aspire builds the image with the project's \" +\n                    $\"own wrapper so the container uses the tool version the repository pins. Generate one \" +\n                    $\"with {JavaHostingExtensions.GenerateWrapperCommand(tool)}, or point at an existing \" +\n                    \"wrapper with WithWrapperPath.\");\n            }\n\n            // The build stage is Linux, so a Windows batch wrapper cannot run there even though it is\n            // the right choice on the developer's machine. Maven and Gradle ship the POSIX script\n            // alongside the batch one under the same base name, so prefer that sibling and only fail\n            // when it is genuinely absent.\n            // https://maven.apache.org/wrapper/ and https://docs.gradle.org/current/userguide/gradle_wrapper.html\n            if (Path.GetExtension(relative) is \".cmd\" or \".bat\")\n            {\n                var posixSibling = relative[..^Path.GetExtension(relative).Length];\n\n                if (!File.Exists(Path.Combine(appDirectory, posixSibling.Replace('/', Path.DirectorySeparatorChar))))\n                {\n                    throw new DistributedApplicationException(\n                        $\"Java application '{resource.Name}' cannot be published because its wrapper \" +\n                        $\"'{relative}' is a Windows batch script and the container build stage is Linux. \" +\n                        $\"No '{posixSibling}' was found next to it. Generate the wrapper with \" +\n                        $\"{JavaHostingExtensions.GenerateWrapperCommand(tool)} so both scripts are present.\");\n                }\n\n                relative = posixSibling;\n            }\n\n            // A Dockerfile COPY takes its arguments separated by whitespace and has no quoted form here,\n            // so a wrapper path containing whitespace would copy two nonexistent paths instead of one real\n            // one. Rejecting it names the problem, rather than failing later inside the build with \"no such\n            // file or directory\" for a path the author never wrote.\n            if (relative.Any(char.IsWhiteSpace))\n            {\n                throw new DistributedApplicationException(\n                    $\"Java application '{resource.Name}' cannot be published because its wrapper path \" +\n                    $\"'{relative}' contains whitespace, which a Dockerfile COPY instruction cannot \" +","sourceCodeStart":1063,"sourceCodeEnd":1099,"githubUrl":"https://github.com/microsoft/aspire/blob/25830f84bd145686607ad00c057b3f84e2e51d43/src/Aspire.Hosting.Java/JavaDockerfileGenerator.cs#L1063-L1099","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Generate the wrapper with JavaHostingExtensions.GenerateWrapperCommand(tool) (mvn wrapper:wrapper / gradle wrapper) so both the POSIX and Windows scripts exist.","Add/commit the extension-less POSIX wrapper (mvnw or gradlew) next to the .cmd/.bat file in the build context.","Point WithWrapperPath at an existing POSIX wrapper inside the app directory."],"exampleFix":"// before\n.WithWrapperPath(\"mvnw.cmd\"); // only the .cmd exists\n// after\n// regenerate so mvnw + mvnw.cmd both exist\n.WithWrapperPath(\"mvnw\");","handlingStrategy":"validation","validationCode":"var wrapper = \"mvnw.cmd\";\nvar posix = Path.ChangeExtension(wrapper, null);\nif (wrapper.EndsWith(\".cmd\") || wrapper.EndsWith(\".bat\"))\n{\n    if (!File.Exists(posix))\n        Console.WriteLine($\"Missing POSIX wrapper '{posix}' for Linux container builds\");\n}","typeGuard":null,"tryCatchPattern":"try { /* publish */ }\ncatch (DistributedApplicationException ex) when (ex.Message.Contains(\"Windows batch script\"))\n{ /* generate both wrapper scripts, then republish */ }","preventionTips":["Always generate wrappers with the official tool so both POSIX and .cmd variants exist","On Windows, still commit the extension-less mvnw/gradlew script","Test container publishes from a Linux shell or CI to catch POSIX gaps"],"tags":["java","wrapper","windows","linux","publish"],"backgroundTag":"unsupported-platform","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"}