apache/hadoop · error · PathIOException
Cannot delete root path
Error message
Cannot delete root path
What it means
Thrown by AliyunOSSFileSystem.rejectRootDirectoryDelete(): a delete targeted the bucket root ('/'), the bucket is not empty, and recursive=false. Deleting an entire bucket's contents implicitly is destructive, so the connector raises PathIOException(bucket, "Cannot delete root path") instead. (An empty root returns true; recursive=true is allowed to proceed.)
Source
Thrown at hadoop-tools/hadoop-aliyun/src/main/java/org/apache/hadoop/fs/aliyun/oss/AliyunOSSFileSystem.java:251
* attempt to continue with the delete operation: deleting root
* directories is never allowed. This method simply implements
* the policy of when to return an exit code versus raise an exception.
* @param isEmptyDir empty directory or not
* @param recursive recursive flag from command
* @return a return code for the operation
* @throws PathIOException if the operation was explicitly rejected.
*/
private boolean rejectRootDirectoryDelete(boolean isEmptyDir,
boolean recursive) throws IOException {
LOG.info("oss delete the {} root directory of {}", bucket, recursive);
if (isEmptyDir) {
return true;
}
if (recursive) {
return false;
} else {
// reject
throw new PathIOException(bucket, "Cannot delete root path");
}
}
private void createFakeDirectoryIfNecessary(Path f) throws IOException {
String key = pathToKey(f);
if (StringUtils.isNotEmpty(key) && !exists(f)) {
LOG.debug("Creating new fake directory at {}", f);
mkdir(pathToKey(f.getParent()));
}
}
@Override
public FileStatus getFileStatus(Path path) throws IOException {
Path qualifiedPath = path.makeQualified(uri, workingDir);
String key = pathToKey(qualifiedPath);
// Root always exists
if (key.length() == 0) {View on GitHub (pinned to 2add963021)
Solutions
- Target the specific subdirectory to delete (oss://bucket/prefix) instead of the bucket root
- If wiping the bucket is truly intended, pass recursive=true with extreme care, or delete via the OSS console/API
- Constrain cleanup code to never construct a delete on the root path; assert path depth before calling delete
Example fix
// before
fs.delete(new Path("oss://my-bucket/"), false); // Cannot delete root path
// after
fs.delete(new Path("oss://my-bucket/dataset/"), true); Defensive patterns
Strategy: validation
Validate before calling
Path toDelete = path;
if (toDelete.isRoot() || toDelete.depth() <= 1) {
throw new IOException("Refusing to delete bucket root: " + toDelete);
}
fs.delete(toDelete, true); Try / catch
catch (PathIOException e) { /* root-delete guard tripped: never widen; fix the caller's path construction */ throw e; } Prevention
- Assert path depth before constructing delete calls in cleanup code
- Point cleanup at concrete dataset prefixes, never at oss://bucket or oss://bucket/
When it happens
Trigger: Calling fs.delete(new Path("oss://bucket/"), false) — directly or via 'hadoop fs -rm oss://bucket' — when any object exists in the bucket; generic cleanup code that walks to the filesystem root and deletes what it sees.
Common situations: Recursive cleanup routines that reach the root after deleting children; tools that call delete on an empty-string path; guarding against accidental bucket wipes in production data lakes.
Related errors
- Cannot remove directory {f}: It is not empty!
- Can not delete root path
- Credentials should not be null.
- Invalid credentials
- Stream closed.
AI-assisted analysis of apache/hadoop@2add963021 (2026-08-22).
Data as JSON: /api/errors/1469ff1958720b4c.
Report an issue: GitHub.