spring-projects/spring-boot · error · GradleException
Failed to add to
Error message
Failed to add {} to {} What it means
Thrown inside BootZipCopyAction's per-entry processing (the FileCopyDetails visitor) when writeLoaderEntriesIfNecessary, processDirectory, or processFile throws an IOException for a specific entry. Unlike error [8] (whole-archive failure), this names the individual entry (details) that failed, plus the target archive. The GradleException wraps the IOException with both the failing entry and the output.
Solutions
- Run 'gradle clean build' to ensure source files are fresh and not locked.
- Examine the 'details' value in the message to identify which specific file/entry is failing and check its readability.
- Ensure the spring-boot-loader dependency version is consistent with the plugin version (no version conflicts).
- Move the build off a network filesystem if you see intermittent I/O errors.
- Disable file-locking tools or antivirus for the build directory.
Defensive patterns
Strategy: try-catch
Validate before calling
// Verify all source files in the copy spec are readable before building.
tasks.bootJar.inputs.files.each { f ->
if (f.exists() && !f.canRead()) {
throw new GradleException("Unreadable input: " + f)
}
} Try / catch
// Catch and inspect the failing entry from the message.
try {
bootJarTask.execute();
} catch (GradleException ex) {
if (ex.getMessage()?.startsWith("Failed to add ")) {
// parse entry name, check readability, retry after clean
}
throw ex;
} Prevention
- Run 'gradle clean build' to avoid stale/locked source files.
- Ensure the spring-boot-loader version matches the plugin version.
- Build on a local filesystem; avoid network mounts for the build directory.
When it happens
Trigger: An IOException while writing a specific file or directory entry into the archive: e.g. the source file is unreadable, the zip entry stream fails, or writing the loader entries (spring-boot-loader classes) encounters an I/O error.
Common situations: A source file in the build output was deleted or locked between the copy spec resolution and the actual write (race with clean/rebuild). The spring-boot-loader JAR is corrupted or being modified during the build. Network filesystem I/O errors. The entry path is too long or contains characters the zip implementation rejects.
Related errors
- Failed to create
- Failed to get mode from FileCopyDetails
- Failed to read main class name from
- Error reading Docker configuration file
- Failed to get dir mode from CopySpec
AI-assisted analysis of spring-projects/spring-boot@270dfe353f (2026-08-11).
Data as JSON: /api/errors/78da5af1948daf8d.
Report an issue: GitHub.
Appendix: source
Thrown at build-plugin/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/BootZipCopyAction.java:222
this.layerIndex = (BootZipCopyAction.this.layerResolver != null)
? new LayersIndex(BootZipCopyAction.this.layerResolver.getLayers()) : null;
}
void process(FileCopyDetails details) {
if (skipProcessing(details)) {
return;
}
try {
writeLoaderEntriesIfNecessary(details);
if (details.isDirectory()) {
processDirectory(details);
}
else {
processFile(details);
}
}
catch (IOException ex) {
throw new GradleException("Failed to add " + details + " to " + BootZipCopyAction.this.output, ex);
}
}
private boolean skipProcessing(FileCopyDetails details) {
return BootZipCopyAction.this.exclusions.isSatisfiedBy(details)
|| (this.writtenLoaderEntries != null && this.writtenLoaderEntries.isWrittenDirectory(details));
}
private void processDirectory(FileCopyDetails details) throws IOException {
String name = details.getRelativePath().getPathString();
ZipArchiveEntry entry = new ZipArchiveEntry(name + '/');
prepareEntry(entry, name, getTime(details), getDirMode(details));
this.out.putArchiveEntry(entry);
this.out.closeArchiveEntry();
this.writtenDirectories.add(name);
}
private void processFile(FileCopyDetails details) throws IOException {View on GitHub (pinned to 270dfe353f)