apache/hadoop · error · IOException
Found non-empty trash root at. Rename or delete it, then try
Error message
Found non-empty trash root at. Rename or delete it, then try again.
What it means
checkTrashRootAndRemoveIfEmpty lists the directory's trash root; if it contains entries it deletes nothing and throws IOException telling you to rename or delete the trash first. This runs on the disallowSnapshot path: HDFS refuses to turn off snapshottability (and implicitly remove the per-directory .Trash) while the trash still holds live content, so recoverable deleted files are not silently destroyed. FileNotFoundException and AccessControlException from the listing are swallowed (no trash or no permission means nothing to check).
Source
Thrown at hadoop-hdfs-project/hadoop-hdfs-client/src/main/java/org/apache/hadoop/hdfs/DistributedFileSystem.java:2325
// 2) returns empty array: the trash path is an empty directory.
// 3) returns non-empty array, len >= 2: the trash root is not empty.
// 4) returns non-empty array, len == 1:
// i) if the element's path is exactly p, the trash path is not a dir.
// e.g. a file named .Trash. Ignore.
// ii) if the element's path isn't p, the trash root is not empty.
FileStatus[] fileStatuses = listStatus(trashRoot);
if (fileStatuses.length == 0) {
DFSClient.LOG.debug("Removing empty trash root {}", trashRoot);
delete(trashRoot, false);
} else {
if (fileStatuses.length == 1
&& !fileStatuses[0].isDirectory()
&& fileStatuses[0].getPath().toUri().getPath().equals(
trashRoot.toString())) {
// Ignore the trash path because it is not a directory.
DFSClient.LOG.warn("{} is not a directory. Ignored.", trashRoot);
} else {
throw new IOException("Found non-empty trash root at " +
trashRoot + ". Rename or delete it, then try again.");
}
}
} catch (FileNotFoundException | AccessControlException ignored) {
}
}
@Override
public Path createSnapshot(final Path path, final String snapshotName)
throws IOException {
statistics.incrementWriteOps(1);
storageStatistics.incrementOpCounter(OpType.CREATE_SNAPSHOT);
Path absF = fixRelativePart(path);
return new FileSystemLinkResolver<Path>() {
@Override
public Path doCall(final Path p) throws IOException {
return new Path(dfs.createSnapshot(getPathName(p), snapshotName));
}View on GitHub (pinned to 2add963021)
Solutions
- Empty the trash root first: delete or move the contents of the directory's .Trash (fs -rmr/-mv of the trash entries), then retry disallowSnapshot.
- Wait for the trash emptier (NameNode trash interval, fs.trash.interval) to purge, then retry.
- If the trash must be kept, rename the .Trash directory elsewhere before disallowing snapshots.
- Verify with listStatus on the trash root that it is empty (or holds only a non-directory artifact, which is ignored) before calling disallowSnapshot.
Example fix
// before
hdfs.disallowSnapshot(path); // IOException: Found non-empty trash root ...
// after
Path trashRoot = new Path(path, ".Trash");
FileStatus[] entries = hdfs.listStatus(trashRoot);
for (FileStatus e : entries) {
hdfs.delete(e.getPath(), true); // purge deliberately
}
hdfs.disallowSnapshot(path); Defensive patterns
Strategy: validation
Validate before calling
Path trashRoot = new Path(path, ".Trash");
try {
FileStatus[] entries = fs.listStatus(trashRoot);
boolean emptyOrIgnorable = entries.length == 0
|| (entries.length == 1 && !entries[0].isDirectory());
if (!emptyOrIgnorable) {
// purge or relocate trash entries before disallowSnapshot
}
} catch (FileNotFoundException ok) {
// no trash root: safe
} Try / catch
try {
hdfs.disallowSnapshot(path);
} catch (IOException e) {
if (e.getMessage() != null && e.getMessage().contains("non-empty trash root")) {
// purge/rename trash root, then retry disallowSnapshot
} else throw e;
} Prevention
- Check the directory's .Trash is empty before disabling snapshots.
- Schedule snapshot teardown after trash emptier runs, not right after mass deletes.
- Never rely on disallowSnapshot to implicitly delete recoverable trash content.
When it happens
Trigger: Calling disallowSnapshot (directly or via HdfsAdmin) on a snapshottable directory whose in-directory trash root (e.g., .Trash for encryption zones / in-dir trash feature) contains files; typically because users deleted files into that trash and they have not expired or been purged.
Common situations: Encryption zones using per-zone .Trash where users rely on trash recovery; retention scripts disabling snapshots right after mass deletes before trash empties; ops flipping snapshottable dirs off during migration with non-empty trash.
Related errors
- Cannot perform snapshot operations on a symlink to a non-Dis
- {} doesn't support createSnapshot
- {} doesn't support renameSnapshot
- {} doesn't support deleteSnapshot
- '{}' copy from '/.reserved/raw' to non '/.reserved/raw'. Eit
AI-assisted analysis of apache/hadoop@2add963021 (2026-08-22).
Data as JSON: /api/errors/1b95d7fca7b43fe6.
Report an issue: GitHub.