spring-projects/spring-boot · error · GradleException
Failed to add {} to {}
Error message
Failed to add {} to {} What it means
Thrown by BootZipCopyAction.Processor.process() when writing a single FileCopyDetails into the archive raises IOException, wrapped as GradleException naming both the entry (details) and the target archive. It is per-entry granularity: the message tells you exactly which file could not be added to which archive.
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 5b2dbdbb8b)
Solutions
- Inspect the message for the specific entry path and verify that file is readable and present.
- Run ./gradlew clean to ensure inputs are regenerated from scratch.
- If the failing entry is a dependency jar, re-resolve dependencies (--refresh-dependencies) to replace a corrupt cached artifact.
- Check for locked/missing source files (IDE/OS-level) and free disk space.
Example fix
// shell: reproduce with clean + refresh deps // ./gradlew clean bootJar --refresh-dependencies --info
Defensive patterns
Strategy: try-catch
Validate before calling
// Pre-check that all inputs to bootJar are readable
sourceSets.main.get().output.files.forEach { d ->
require(d.canRead()) { "Cannot read source dir ${d.absolutePath}" }
}
configurations.runtimeClasspath.get().files.forEach { f ->
require(f.canRead()) { "Cannot read dependency ${f.absolutePath}" }
}
Try / catch
try {
tasks.named("bootJar").get().copy()
} catch (ex: org.gradle.api.GradleException) {
if (ex.message?.startsWith("Failed to add ") == true) {
logger.error("A specific entry could not be added; see the file named in the message.")
}
throw ex
}
Prevention
- Run ./gradlew clean so all inputs are freshly produced.
- Use --refresh-dependencies when a cached dependency jar is suspect.
- Avoid modifying/killing source files during the build.
When it happens
Trigger: For each entry, process() writes loader/directory/file; if details.copyTo(out) or putArchiveEntry/closeArchiveEntry throws IOException, line 222 wraps it with 'Failed to add <details> to <output>'.
Common situations: A source file vanishes between scanning and copying (mid-build deletion); a corrupted/locked input jar; oversized entry; filesystem errors on the build volume; an input dependency is unreadable.
Related errors
- Failed to create {}
- Failed to read '{}'
- Failed to read main class name from '{}'
- Failed to get dir mode from CopySpec
- Failed to get file mode from CopySpec
AI-assisted analysis of spring-projects/spring-boot@5b2dbdbb8b (2026-08-04).
Data as JSON: /data/errors/78da5af1948daf8d.json.
Report an issue: GitHub.