{"record":{"id":"578364932d02cc68","repo":"GoogleContainerTools/jib","slug":"both-bootjar-and-jar-tasks-are-enabled-but-th","errorCode":null,"errorMessage":"Both 'bootJar' and 'jar' tasks are enabled, but they write their jar file into the same location at ${jarPath}. Did you forget to set 'archiveClassifier' on either task?","messagePattern":"Both 'bootJar' and 'jar' tasks are enabled, but they write their jar file into the same location at (.+?)\\. Did you forget to set 'archiveClassifier' on either task\\?","errorType":"exception","errorClass":"GradleException","httpStatus":null,"severity":"error","filePath":"jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/JibPlugin.java","lineNumber":173,"sourceCode":"            if (bootWarTask != null) {\n              jibDependencies.add(bootWarTask);\n            }\n          } else if (\"packaged\".equals(jibExtension.getContainerizingMode())) {\n            // Have all tasks depend on the 'jar' task.\n            TaskProvider<Task> jarTask = projectAfterEvaluation.getTasks().named(\"jar\");\n            jibDependencies.add(jarTask);\n\n            if (projectAfterEvaluation.getPlugins().hasPlugin(\"org.springframework.boot\")) {\n              Task bootJarTask = projectAfterEvaluation.getTasks().getByName(\"bootJar\");\n\n              if (bootJarTask.getEnabled()) {\n                String bootJarPath = bootJarTask.getOutputs().getFiles().getAsPath();\n                String jarPath = jarTask.get().getOutputs().getFiles().getAsPath();\n                if (bootJarPath.equals(jarPath)) {\n                  if (!jarTask.get().getEnabled()) {\n                    ((Jar) jarTask.get()).getArchiveClassifier().set(\"original\");\n                  } else {\n                    throw new GradleException(\n                        \"Both 'bootJar' and 'jar' tasks are enabled, but they write their jar file \"\n                            + \"into the same location at \"\n                            + jarPath\n                            + \". Did you forget to set 'archiveClassifier' on either task?\");\n                  }\n                }\n              }\n              jarTask.get().setEnabled(true);\n            }\n          }\n\n          SourceSet mainSourceSet =\n              projectAfterEvaluation\n                  .getExtensions()\n                  .getByType(SourceSetContainer.class)\n                  .getByName(SourceSet.MAIN_SOURCE_SET_NAME);\n          jibDependencies.add(mainSourceSet.getRuntimeClasspath());\n          jibDependencies.add(","sourceCodeStart":155,"sourceCodeEnd":191,"githubUrl":"https://github.com/GoogleContainerTools/jib/blob/fb949e2676afbbd7dd7a1ef61e20251931325654/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/JibPlugin.java#L155-L191","documentation":"When the Spring Boot plugin is present, Jib checks that the bootJar and jar tasks do not write to the same output path. If both are enabled and their output jars collide, Jib cannot tell which jar to containerize and throws GradleException, suggesting the user set a distinct archiveClassifier.","triggerScenarios":"Applying both com.google.cloud.tools.jib and Spring Boot's plugin where bootJar and jar tasks are both enabled and produce jars at the same path (bootJarPath.equals(jarPath)) and the plain jar task is not disabled; triggered during Jib task execution's afterEvaluate/action hook.","commonSituations":"Spring Boot 2.5+ projects where jar and bootJar both build <name>-<version>.jar unless archiveClassifier is set; upgrading Spring Boot after which Jib's older workaround (disabling jar) no longer applies; custom jar task configuration overriding archiveClassifier.","solutions":["Set a distinct archiveClassifier on the plain jar task: `jar { archiveClassifier.set('plain') }` or bootJar `archiveClassifier.set('boot')`","Disable the plain jar task if only the boot jar is needed: `jar { enabled = false }` (Jib then auto-sets classifier 'original' if needed)","Ensure only one of the two tasks writes to the same destination path","Pin a Jib version compatible with your Spring Boot version's default jar naming"],"exampleFix":"// before\ntasks.jar { enabled = true } // same path as bootJar\n// after\ntasks.jar {\n  archiveClassifier.set('plain')\n}","handlingStrategy":"validation","validationCode":"def bootJar = tasks.findByName('bootJar'), jar = tasks.findByName('jar')\nif (bootJar && jar && jar.enabled && bootJar.enabled &&\n    bootJar.outputs.files.asPath == jar.outputs.files.asPath) {\n  jar.archiveClassifier.set('plain')\n  logger.lifecycle('Set archiveClassifier=plain on jar to avoid Jib bootJar/jar conflict')\n}","typeGuard":null,"tryCatchPattern":"try {\n  jib.build()\n} catch (GradleException e) {\n  if (e.message.contains(\"Both 'bootJar' and 'jar' tasks are enabled\")) {\n    logger.error('Set distinct archiveClassifier or disable the plain jar task')\n  } else { throw e }\n}","preventionTips":["In Spring Boot 2.5+ projects, always configure jar { archiveClassifier.set('plain') } or jar { enabled = false }","Re-check jar task config after upgrading Spring Boot or Jib","Add an afterEvaluate check that bootJar and jar output paths differ","Never let two jar tasks share the same destination"],"tags":["gradle","spring-boot","jib","task-conflict"],"backgroundTag":"conflicting-config-options","analyzedSha":"fb949e2676afbbd7dd7a1ef61e20251931325654","analyzedAt":"2026-09-06T14:04:09.491Z","contentChangedAt":"2026-09-06T14:04:09.491Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}