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

  1. Run 'gradle clean build' to ensure source files are fresh and not locked.
  2. Examine the 'details' value in the message to identify which specific file/entry is failing and check its readability.
  3. Ensure the spring-boot-loader dependency version is consistent with the plugin version (no version conflicts).
  4. Move the build off a network filesystem if you see intermittent I/O errors.
  5. 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

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


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)