{"record":{"id":"eaed38656d57dc41","repo":"microsoft/aspire","slug":"the-java-application-resource-name-cannot-be-published-eaed38","errorCode":null,"errorMessage":"The Java application '{resource.Name}' cannot be published because no build tool was found. Add a pom.xml, build.gradle, build.gradle.kts, settings.gradle, or settings.gradle.kts to '{appDirectory}', or call WithMavenBuild or WithGradleBuild to state how the deployable JAR is produced.","messagePattern":"The Java application '(.+?)' cannot be published because no build tool was found\\. Add a pom\\.xml, build\\.gradle, build\\.gradle\\.kts, settings\\.gradle, or settings\\.gradle\\.kts to '(.+?)', or call WithMavenBuild or WithGradleBuild to state how the deployable JAR is produced\\.","errorType":"exception","errorClass":"DistributedApplicationException","httpStatus":null,"severity":"error","filePath":"src/Aspire.Hosting.Java/JavaDockerfileGenerator.cs","lineNumber":1177,"sourceCode":"            }\n\n            // A launch goal such as spring-boot:run or bootRun identifies the tool but never packages, so\n            // only the tool is taken from it and the packaging arguments are defaulted.\n            if (resource.TryGetLastAnnotation<JavaBuildToolAnnotation>(out var buildTool))\n            {\n                return (buildTool.Tool, DefaultPackageArgs(buildTool.Tool));\n            }\n\n            // Left for an application added with a prebuilt JAR path and no build configuration: the\n            // container still has to produce that JAR, so the tool comes from what is on disk. This uses\n            // the same detector as run mode so publish cannot silently choose Maven for an ambiguous\n            // directory that run mode rejects.\n            if (DetectBuildToolForPublish(resource, appDirectory) is { } detectedTool)\n            {\n                return (detectedTool, DefaultPackageArgs(detectedTool));\n            }\n\n            throw new DistributedApplicationException(\n                $\"The Java application '{resource.Name}' cannot be published because no build tool was found. \" +\n                $\"Add a pom.xml, build.gradle, build.gradle.kts, settings.gradle, or settings.gradle.kts to '{appDirectory}', \" +\n                \"or call WithMavenBuild or WithGradleBuild \" +\n                \"to state how the deployable JAR is produced.\");\n        }\n\n        private static string[] DefaultPackageArgs(JavaBuildTool tool) => tool switch\n        {\n            // -B disables the ANSI progress output that renders as noise in a build log, and -ntp drops\n            // the per-artifact download lines. Tests are skipped because the container build produces a\n            // deployable artifact; running the test suite belongs to CI, not to `aspire publish`.\n            JavaBuildTool.Maven => [\"-B\", \"-ntp\", \"-DskipTests\", \"package\"],\n            JavaBuildTool.Gradle => [\"-x\", \"test\", \"build\"],\n            _ => throw new UnreachableException()\n        };\n\n        /// <summary>\n        /// Emits a shell command that resolves <paramref name=\"outputGlob\"/> to exactly one JAR and copies","sourceCodeStart":1159,"sourceCodeEnd":1195,"githubUrl":"https://github.com/microsoft/aspire/blob/25830f84bd145686607ad00c057b3f84e2e51d43/src/Aspire.Hosting.Java/JavaDockerfileGenerator.cs#L1159-L1195","documentation":"In the no-detected-build-tool-annotation path, publish tries configured tool, then filesystem detection; if neither yields a tool it throws with an expanded message that also suggests WithMavenBuild/WithGradleBuild. Like error 995, publish cannot proceed without knowing how to produce the deployable JAR.","triggerScenarios":"Publishing an AddJavaApp resource with no JavaDetectedBuildToolAnnotation source path leading to a tool: no build-tool annotation from run mode and DetectBuildToolForPublish finds no pom.xml/gradle files in appDirectory.","commonSituations":"Same as 995: wrong directory, build files elsewhere, exotic build setups; also resources created via paths that never ran run-mode detection.","solutions":["Call WithMavenBuild or WithGradleBuild on the resource to declare the build tool explicitly.","Add a pom.xml or Gradle build/settings file to the directory given to AddJavaApp.","Point AddJavaApp at the directory that actually contains the build file."],"exampleFix":"// before\nbuilder.AddJavaApp(\"api\", \"src/api\"); // no pom.xml or gradle files\n// after\nbuilder.AddJavaApp(\"api\", \"src/api\")\n    .WithGradleBuild(); // or add build.gradle.kts to src/api","handlingStrategy":"validation","validationCode":"var dir = \"src/api\";\nstring[] markers = [\"pom.xml\", \"build.gradle\", \"build.gradle.kts\", \"settings.gradle\", \"settings.gradle.kts\"];\nif (!markers.Any(m => File.Exists(Path.Combine(dir, m))))\n    resourceBuilder.WithGradleBuild(); // declare the tool explicitly","typeGuard":null,"tryCatchPattern":"try { /* publish */ }\ncatch (DistributedApplicationException ex) when (ex.Message.Contains(\"WithMavenBuild or WithGradleBuild\"))\n{ /* declare the build tool explicitly and republish */ }","preventionTips":["Prefer explicit WithMavenBuild/WithGradleBuild in publish-focused apps","Standardize on Maven or Gradle marker files in every Java module","Validate app directory contents in CI before publishing"],"tags":["java","build-tool","publish","detection"],"backgroundTag":"missing-required-config","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"}