apache/hadoop · error · IOException
Cannot rename %s to %s, %s is a file
Error message
Cannot rename %s to %s, %s is a file
What it means
When the destination of a rename does not exist, CosN stats dst's parent; if that parent exists as a FILE, rename throws IOException('Cannot rename <src> to <dst>, <dstParent> is a file') — the destination cannot sit beneath a file (ENOTDIR). If the parent is missing entirely, getFileStatus(parent) instead propagates FileNotFoundException out of rename, which is a separate failure mode.
Source
Thrown at hadoop-cloud-storage-project/hadoop-cos/src/main/java/org/apache/hadoop/fs/cosn/CosNFileSystem.java:679
} catch (FileNotFoundException e) {
statuses = null;
}
if (null != statuses && statuses.length > 0) {
LOG.debug("Cannot rename source file: [{}] to dest file: [{}], "
+ "because the file already exists.", src, dst);
throw new FileAlreadyExistsException(
String.format(
"File: %s already exists", dst
)
);
}
}
} catch (FileNotFoundException e) {
// destination path not exists
Path tempDstParentPath = dst.getParent();
FileStatus dstParentStatus = this.getFileStatus(tempDstParentPath);
if (!dstParentStatus.isDirectory()) {
throw new IOException(String.format(
"Cannot rename %s to %s, %s is a file", src, dst, dst.getParent()
));
}
// The default root directory is definitely there.
}
boolean result;
if (srcFileStatus.isDirectory()) {
result = this.copyDirectory(src, dst);
} else {
result = this.copyFile(src, dst);
}
if (!result) {
//Since rename is a non-atomic operation, after copy fails,
// it is not allowed to delete the data of the original path.
return false;
} else {View on GitHub (pinned to 2add963021)
Solutions
- Delete or relocate the file occupying the destination's parent path.
- After removing the conflict, fs.mkdirs(dst.getParent()) and retry the rename.
- Choose a destination whose full prefix chain contains only real directories.
Example fix
// before
fs.rename(new Path('/a/f'), new Path('/b/g')); // IOException: ... /b is a file
// after
Path parent = new Path('/b');
if (fs.exists(parent) && fs.getFileStatus(parent).isFile()) {
fs.delete(parent, false);
}
fs.mkdirs(parent);
fs.rename(new Path('/a/f'), new Path('/b/g')); Defensive patterns
Strategy: validation
Validate before calling
Path parent = dst.getParent();
if (fs.exists(parent) && !fs.getFileStatus(parent).isDirectory()) {
throw new IllegalStateException('Destination parent is a file: ' + parent);
}
if (!fs.exists(parent)) { fs.mkdirs(parent); } Try / catch
try {
fs.rename(src, dst);
} catch (IOException e) {
if (e.getMessage() != null && e.getMessage().contains('is a file')) {
fs.delete(dst.getParent(), false);
fs.mkdirs(dst.getParent());
fs.rename(src, dst);
} else { throw e; }
} Prevention
- Validate the full destination prefix chain before renames
- Never let a destination parent exist as a file in your layouts
- mkdirs the destination parent as part of move utilities
When it happens
Trigger: fs.rename('/a/f', '/b/g') where '/b' is an existing file object; renaming into a 'directory' path that was previously created as a file.
Common situations: Destination tree half-created with files at directory levels; a partition path used both as file and directory across runs of a pipeline.
Related errors
- Can't make directory for path '%s', it is a file.
- Source path and dest path refer the same file or directory
- It is not allowed to rename a parent directory: %s to its su
- File: %s already exists
- can not copy a directory to a subdirectory of self
AI-assisted analysis of apache/hadoop@2add963021 (2026-08-22).
Data as JSON: /api/errors/c75db875e1895365.
Report an issue: GitHub.