gradle/gradle · error · UncheckedIOException
Failed to clean up stale outputs
Error message
Failed to clean up stale outputs
What it means
Before executing tasks, Gradle deletes stale regular files left in task output locations (leftovers from previous runs, or outputs of a task that declared overlapping outputs). StaleOutputCleaner.cleanupOutputs wraps any IOException raised while deleting one of those files into an UncheckedIOException with this message, so the build aborts with the underlying filesystem error as the cause.
Source
Thrown at platforms/software/platform-base/src/main/java/org/gradle/language/base/internal/tasks/StaleOutputCleaner.java:78
OutputsCleaner outputsCleaner = new OutputsCleaner(
deleter,
file -> {
String absolutePath = file.getAbsolutePath();
return prefixes.stream()
.anyMatch(absolutePath::startsWith);
},
dir -> !directoriesToClean.contains(dir)
);
try {
for (File f : filesToDelete) {
if (f.isFile()) {
outputsCleaner.cleanupOutput(f, FileType.RegularFile);
}
}
outputsCleaner.cleanupDirectories();
} catch (IOException e) {
throw new UncheckedIOException("Failed to clean up stale outputs", e);
}
return outputsCleaner.getDidWork();
}
@CheckReturnValue
public static boolean cleanEmptyOutputDirectories(Deleter deleter, Iterable<File> directories, File directoryToClean) {
return cleanEmptyOutputDirectories(deleter, directories, ImmutableSet.of(directoryToClean));
}
@CheckReturnValue
public static boolean cleanEmptyOutputDirectories(Deleter deleter, Iterable<File> directories, Collection<File> directoriesToClean) {
OutputsCleaner outputsCleaner = new OutputsCleaner(
deleter,
file -> false,
dir -> !directoriesToClean.contains(dir)
);
View on GitHub (pinned to 534f27719b)
Solutions
- Run with --stacktrace and read the caused-by IOException to get the exact file path and OS-level reason
- Stop competing processes: gradle --stop for other daemons, close applications/IDEs using build outputs, then re-run
- Fix permissions/ownership so the build user can delete files under the output directories (chown -R, correct Docker volume uid)
- If outputs sit on a read-only or full filesystem, free space or relocate outputs (buildDir, --project-cache-dir)
- Remove overlapping output-directory declarations between tasks so stale-output cleanup is not needed between them
Defensive patterns
Strategy: try-catch
Validate before calling
def outDirs = tasks.withType(JavaCompile).collect { it.destinationDirectory.get().asFile }
outDirs.each { d ->
assert d.isDirectory() && d.canWrite() : "Output dir not writable: $d"
def probe = new File(d, '.delete-probe')
probe.text = 'x'
assert probe.delete() : "Cannot delete files in $d - a lock or permission will break stale-output cleanup"
} Try / catch
try {
// via Tooling API: buildLauncher.forTasks('build').run()
org.gradle.tooling.GradleConnector.newConnector()
.forProjectDirectory(new File('.'))
.connect().newBuild().forTasks('build').run()
} catch (Exception e) {
def root = e
while (root.cause != null && !(root.cause instanceof java.io.IOException)) root = root.cause
if (root.message?.contains('Failed to clean up stale outputs')) {
// release locks: gradle --stop, close apps, then retry once
} else { throw e }
} Prevention
- Run a single Gradle daemon per project; run gradle --stop when switching Gradle versions
- Exclude build/ directories from antivirus real-time scanning on Windows build hosts
- Ensure the CI user owns the workspace volume in containerized builds
- Never declare overlapping output directories between two tasks
When it happens
Trigger: StaleOutputCleaner.cleanupOutputs iterates filesToDelete and calls outputsCleaner.cleanupOutput(f, FileType.RegularFile) inside the try block. Any IOException from that call - a file locked by another process, permission denied on the file or a parent directory, or a read-only filesystem - escapes the loop and is rethrown as UncheckedIOException('Failed to clean up stale outputs', e).
Common situations: Windows build hosts where antivirus, an indexer, or a running IDE holds a lock on a JAR/class file under build/; a second Gradle daemon or a still-running application writing into the same build directory; CI containers where the workspace volume is owned by a different uid; NFS/SMB mounts that deny deletes; full disks.
Related errors
- Unable to generate TOML dependencies file into {}
- Could not write %s content to %s.
- Could not write %s content to %s.
- Could not write %s content to %s.
- %s is already declared as an output property of %s. Cannot a
AI-assisted analysis of gradle/gradle@534f27719b (2026-08-22).
Data as JSON: /api/errors/1f61401e8fa7e061.
Report an issue: GitHub.