spring-projects/spring-boot · error · IllegalStateException
A jar or war file is required for building image
Error message
A jar or war file is required for building image
What it means
IllegalStateException thrown by BuildImageMojo.getArchiveFile when no packaged archive can be located. The plugin first looks for target/<finalName>[<classifier>].<ext> in sourceDirectory, then falls back to the resolved source artifact's file. If neither exists, building a container image is impossible because the image tar needs an actual jar/war to embed.
Solutions
- Bind or run the goal as part of the package phase: `mvn package spring-boot:build-image`.
- Confirm the configured <classifier> (if any) matches an artifact actually produced by the build.
- Verify <finalName> and <sourceDirectory> so getTargetFile resolves to the real archive.
- Ensure the package goal (jar/war packaging) is not skipped and runs in the same lifecycle.
Example fix
// before: mvn spring-boot:build-image // after: mvn clean package spring-boot:build-image
Defensive patterns
Strategy: validation
Validate before calling
// Pre-build check: an archive must exist before build-image:
String ext = "jar".equals(project.getPackaging()) ? "jar" : "war";
File archive = new File(sourceDirectory, finalName + (classifier == null ? "" : "-" + classifier) + "." + ext);
if (!archive.exists()) {
throw new IllegalStateException("Run `mvn package` before build-image; missing " + archive);
} Try / catch
try {
// invoke build-image
} catch (IllegalStateException ex) {
if ("A jar or war file is required for building image".equals(ex.getMessage())) {
// run package first, then retry
}
throw ex;
} Prevention
- Always invoke build-image as `mvn package spring-boot:build-image`.
- Bind build-image to the package phase in <executions>.
- Double-check <classifier> and <finalName> against the produced artifact.
When it happens
Trigger: Invoking spring-boot:build-image before the package phase produced an archive; classifier mismatch so getTargetFile returns a non-existent file and getSourceArtifact(classifier).getFile() is also null; package ran in a forked lifecycle leaving no file at the expected path.
Common situations: Calling build-image directly without `mvn package spring-boot:build-image`; using a <classifier> that doesn't correspond to any produced artifact; repackaging skipped; outputDirectory/finalName customized so the plugin looks in the wrong place; CI step ordering omits package.
Related errors
- Error packaging archive for image
- Source file is not available, make sure 'package' runs as…
- Invalid Docker configuration, either context or host can be…
- Process terminated with exit code
- Can't parse ' ' to instant
AI-assisted analysis of spring-projects/spring-boot@270dfe353f (2026-08-11).
Data as JSON: /api/errors/c4630792c581be80.
Report an issue: GitHub.
Appendix: source
Thrown at build-plugin/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/BuildImageMojo.java:325
image.setImagePlatform(this.imagePlatform);
}
return customize(image.getBuildRequest(this.project.getArtifact(), content));
}
private TarArchive getApplicationContent(Owner owner, Libraries libraries, ImagePackager imagePackager) {
ImagePackager packager = getConfiguredPackager(() -> imagePackager);
return new PackagedTarArchive(owner, libraries, packager);
}
private File getArchiveFile() {
// We can't use 'project.getArtifact().getFile()' because package can be done in a
// forked lifecycle and will be null
File archiveFile = getTargetFile(this.finalName, this.classifier, this.sourceDirectory);
if (!archiveFile.exists()) {
archiveFile = getSourceArtifact(this.classifier).getFile();
}
if (!archiveFile.exists()) {
throw new IllegalStateException("A jar or war file is required for building image");
}
return archiveFile;
}
/**
* Return the {@link File} to use to back up the original source.
* @return the file to use to back up the original source
*/
private @Nullable File getBackupFile() {
// We can't use 'project.getAttachedArtifacts()' because package can be done in a
// forked lifecycle and will be null
if (this.classifier != null) {
File backupFile = getTargetFile(this.finalName, null, this.sourceDirectory);
if (backupFile.exists()) {
return backupFile;
}
Artifact source = getSourceArtifact(null);
if (!this.classifier.equals(source.getClassifier())) {View on GitHub (pinned to 270dfe353f)