{"record":{"id":"2f775cdbd288b441","repo":"microsoft/aspire","slug":"java-application-resource-name-cannot-be-published-because-2f775c","errorCode":null,"errorMessage":"Java application '{resource.Name}' cannot be published because its {wrapper} has no '{supportPath}/wrapper/{propertiesName}'. That file pins the build tool version the image is built with. Regenerate the wrapper with {JavaHostingExtensions.GenerateWrapperCommand(tool)} and commit the whole '{supportPath}' directory.","messagePattern":"Java application '(.+?)' cannot be published because its (.+?) has no '(.+?)/wrapper/(.+?)'\\. That file pins the build tool version the image is built with\\. Regenerate the wrapper with (.+?) and commit the whole '(.+?)' directory\\.","errorType":"exception","errorClass":"DistributedApplicationException","httpStatus":null,"severity":"error","filePath":"src/Aspire.Hosting.Java/JavaDockerfileGenerator.cs","lineNumber":1009,"sourceCode":"            // The support directory sits next to the wrapper script, so a wrapper in a subdirectory of the\n            // context keeps its own .mvn/gradle directory there rather than at the context root.\n            var wrapperDirectory = Path.GetDirectoryName(wrapper.AsSpan());\n            var supportPath = wrapperDirectory.IsEmpty\n                ? supportDirectoryName\n                : $\"{wrapperDirectory}/{supportDirectoryName}\";\n\n            // Both wrappers store the distribution URL in <support>/wrapper/<tool>-wrapper.properties.\n            // https://maven.apache.org/wrapper/ and https://docs.gradle.org/current/userguide/gradle_wrapper.html\n            var propertiesName = $\"{tool.ToString().ToLowerInvariant()}-wrapper.properties\";\n            var propertiesPath = Path.Combine(\n                appDirectory,\n                supportPath.Replace('/', Path.DirectorySeparatorChar),\n                \"wrapper\",\n                propertiesName);\n\n            if (!File.Exists(propertiesPath))\n            {\n                throw new DistributedApplicationException(\n                    $\"Java application '{resource.Name}' cannot be published because its {wrapper} has no \" +\n                    $\"'{supportPath}/wrapper/{propertiesName}'. That file pins the build tool version the \" +\n                    $\"image is built with. Regenerate the wrapper with \" +\n                    $\"{JavaHostingExtensions.GenerateWrapperCommand(tool)} and commit the whole \" +\n                    $\"'{supportPath}' directory.\");\n            }\n\n            return supportPath;\n        }\n\n        /// <summary>\n        /// Resolves the wrapper script as a path relative to the build context.\n        /// </summary>\n        /// <remarks>\n        /// A wrapper is required rather than falling back to a <c>mvn</c>/<c>gradle</c> installed in the\n        /// build image: the wrapper pins the tool version in the repository, so the container image is\n        /// produced by the same version that built the project locally and in CI.\n        /// <para>","sourceCodeStart":991,"sourceCodeEnd":1027,"githubUrl":"https://github.com/microsoft/aspire/blob/25830f84bd145686607ad00c057b3f84e2e51d43/src/Aspire.Hosting.Java/JavaDockerfileGenerator.cs#L991-L1027","documentation":"ResolveWrapperSupportPath requires the wrapper properties file (mvnw wrapper/maven-wrapper.properties or gradle wrapper/gradle-wrapper.properties) to exist in the application directory when publishing with a wrapper. That file pins the build tool version used to build the image; without it the container build would use an unknown tool version, so the generator throws DistributedApplicationException telling you to regenerate the wrapper.","triggerScenarios":"Publishing a Java resource configured to use mvnw/gradlew where the application directory lacks '<supportPath>/wrapper/maven-wrapper.properties' (or gradle-wrapper.properties) — e.g. the wrapper was copied incompletely, .mvn/ or gradle/ was gitignored, or the wrapper was never generated.","commonSituations":"Committing only mvnw/gradlew scripts but not the wrapper/ directory (gitignore patterns like '*.jar' or 'wrapper/' excluding the properties file); creating a fresh repo from scripts only; deleting .mvn or gradle folders during cleanup.","solutions":["Regenerate the wrapper with the documented command (e.g. 'mvn wrapper:wrapper' or 'gradle wrapper') in the application directory and commit the whole wrapper support directory.","Check .gitignore so the wrapper directory (including its .properties and .jar files) is committed.","If you don't need the wrapper, switch the resource configuration to the non-wrapper build tool path."],"exampleFix":"// before: repo contains only ./mvnw (no .mvn/wrapper/maven-wrapper.properties)\n// after\ncd <app directory>\nmvn wrapper:wrapper   # creates .mvn/wrapper/maven-wrapper.properties\ngit add .mvn && git commit -m \"Add Maven wrapper properties\"","handlingStrategy":"validation","validationCode":"var props = useMaven ? \".mvn/wrapper/maven-wrapper.properties\" : \"gradle/wrapper/gradle-wrapper.properties\";\nif (!File.Exists(Path.Combine(appDirectory, props)))\n    throw new InvalidOperationException($\"Wrapper properties missing: {props}. Run the wrapper generation command and commit the wrapper directory.\");","typeGuard":null,"tryCatchPattern":"try { await PublishAsync(...); } catch (DistributedApplicationException ex) when (ex.Message.Contains(\"wrapper\")) { Console.Error.WriteLine(ex.Message); return 1; }","preventionTips":["Commit the entire wrapper support directory (.mvn/wrapper or gradle/wrapper), including .properties and .jar files.","Review .gitignore for patterns that exclude wrapper files.","Run 'mvn wrapper:wrapper' or 'gradle wrapper' after cloning a repo that ships only the wrapper scripts."],"tags":["java","wrapper","file-not-found","publish"],"backgroundTag":"file-not-found","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"}