{"record":{"id":"8d983fc0c26ac282","repo":"microsoft/aspire","slug":"directory-appdirectory-contains-both-maven-and-gradle-build","errorCode":null,"errorMessage":"Directory '{appDirectory}' contains both Maven and Gradle build files, so the build tool for resource '{resourceName}' is ambiguous. Use AddJavaApp and call WithMavenBuild, WithGradleBuild, WithMavenGoal, or WithGradleTask to choose one explicitly.","messagePattern":"Directory '(.+?)' contains both Maven and Gradle build files, so the build tool for resource '(.+?)' is ambiguous\\. Use AddJavaApp and call WithMavenBuild, WithGradleBuild, WithMavenGoal, or WithGradleTask to choose one explicitly\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/Aspire.Hosting.Java/JavaBuildToolResolver.cs","lineNumber":39,"sourceCode":"\n    /// <summary>\n    /// Returns the build tool declared by files in <paramref name=\"appDirectory\"/>, or\n    /// <see langword=\"null\"/> when none is declared.\n    /// </summary>\n    internal static JavaBuildTool? Detect(\n        string appDirectory,\n        string resourceName,\n        Func<string, Exception> createAmbiguityException)\n    {\n        var hasMaven = File.Exists(Path.Combine(appDirectory, \"pom.xml\"));\n        var hasGradle = s_gradleBuildFileNames.Any(fileName => File.Exists(Path.Combine(appDirectory, fileName)));\n\n        // Ambiguous projects are rejected rather than guessed. Maven-first detection made publish produce\n        // a different artifact than run mode for the same directory, while an explicit build or launch API\n        // records the author's choice for both paths.\n        if (hasMaven && hasGradle)\n        {\n            throw createAmbiguityException(\n                $\"Directory '{appDirectory}' contains both Maven and Gradle build files, so the build tool for resource '{resourceName}' is ambiguous. \" +\n                \"Use AddJavaApp and call WithMavenBuild, WithGradleBuild, WithMavenGoal, or WithGradleTask to choose one explicitly.\");\n        }\n\n        return (hasMaven, hasGradle) switch\n        {\n            (true, false) => JavaBuildTool.Maven,\n            (false, true) => JavaBuildTool.Gradle,\n            _ => null\n        };\n    }\n\n    /// <summary>\n    /// Resolves the wrapper selected for a resource on the requested execution platform.\n    /// </summary>\n    /// <remarks>\n    /// The application's own directory wins, then the search walks up to the build root. A Gradle\n    /// multi-project build has exactly one <c>gradlew</c>, next to the <c>settings.gradle</c> that","sourceCodeStart":21,"sourceCodeEnd":57,"githubUrl":"https://github.com/microsoft/aspire/blob/25830f84bd145686607ad00c057b3f84e2e51d43/src/Aspire.Hosting.Java/JavaBuildToolResolver.cs#L21-L57","documentation":"JavaBuildToolResolver.Detect infers whether a Java app directory is Maven- or Gradle-based by looking for build files (pom.xml vs build.gradle/build.gradle.kts with settings files). When both toolchains' files are present the choice is ambiguous, and rather than guessing (which historically caused run and publish to disagree), it throws and asks the author to declare the tool explicitly. The resolver intentionally rejects ambiguous directories instead of silently picking one.","triggerScenarios":"Adding a Java app whose appDirectory contains both a pom.xml and a Gradle build file (build.gradle/build.gradle.kts/settings.gradle) while using AddJavaApp without calling WithMavenBuild, WithGradleBuild, WithMavenGoal, or WithGradleTask.","commonSituations":"Repositories migrated from Maven to Gradle (or vice versa) where the old pom.xml was left behind; monorepo sample directories containing multiple build systems; generated scaffolding that emits both files; copying a Gradle wrapper into a Maven project.","solutions":["Call WithMavenBuild(...) or WithGradleBuild(...) on the AddJavaApp resource to choose the build tool explicitly.","If you use goal/task-level APIs, call WithMavenGoal(...) or WithGradleTask(...) which also disambiguates.","Delete the stale build files for the toolchain you no longer use (e.g. remove pom.xml from a Gradle project).","Move each project's build files into its own directory so appDirectory contains only one toolchain's files."],"exampleFix":"// before\nbuilder.AddJavaApp(\"api\", \"../api\"); // directory has pom.xml AND build.gradle.kts -> throws\n\n// after\nbuilder.AddJavaApp(\"api\", \"../api\")\n       .WithGradleBuild(); // explicit choice resolves the ambiguity","handlingStrategy":"validation","validationCode":"// before calling AddJavaApp, ensure only one toolchain's files exist\nvar hasMaven = Directory.EnumerateFiles(appDirectory, \"pom.xml\", SearchOption.TopDirectoryOnly).Any();\nvar hasGradle = Directory.EnumerateFiles(appDirectory, \"build.gradle*\", SearchOption.TopDirectoryOnly).Any();\nif (hasMaven && hasGradle) throw new InvalidOperationException($\"{appDirectory} has both Maven and Gradle files; remove one or call WithMavenBuild/WithGradleBuild.\");","typeGuard":null,"tryCatchPattern":"try {\n  var app = builder.AddJavaApp(\"api\", \"../api\");\n} catch (InvalidOperationException ex) when (ex.Message.Contains(\"ambiguous\")) {\n  // choose the build tool explicitly via WithMavenBuild/WithGradleBuild and retry\n}","preventionTips":["Always declare WithMavenBuild/WithGradleBuild (or WithMavenGoal/WithGradleTask) on AddJavaApp resources instead of relying on detection.","Delete stale build files after migrating between Maven and Gradle.","Keep one toolchain's files per project directory in monorepos."],"tags":["java","maven","gradle","build-tool","ambiguity"],"backgroundTag":"conflicting-config-options","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"}