apache/hadoop · error · FileAlreadyExistsException
Can't make directory for path: %s, since it is a file.
Error message
Can't make directory for path: %s, since it is a file.
What it means
mkDirRecursively builds the missing ancestors of f bottom-up and, while checking each level, throws FileAlreadyExistsException if an existing entry there is a file. Note a reporting quirk: the message formats the ORIGINAL path f, not the ancestor that conflicted, so the message names the requested directory while the real conflict sits at some parent. Inspect parents when it fires.
Source
Thrown at hadoop-cloud-storage-project/hadoop-cos/src/main/java/org/apache/hadoop/fs/cosn/CosNFileSystem.java:545
* creating the path.
*/
public boolean mkDirRecursively(Path f, FsPermission permission)
throws IOException {
Path absolutePath = makeAbsolute(f);
List<Path> paths = new ArrayList<>();
do {
paths.add(absolutePath);
absolutePath = absolutePath.getParent();
} while (absolutePath != null);
for (Path path : paths) {
if (path.equals(new Path(CosNFileSystem.PATH_DELIMITER))) {
break;
}
try {
FileStatus fileStatus = getFileStatus(path);
if (fileStatus.isFile()) {
throw new FileAlreadyExistsException(
String.format("Can't make directory for path: %s, "
+ "since it is a file.", f));
}
if (fileStatus.isDirectory()) {
break;
}
} catch (FileNotFoundException e) {
LOG.debug("Making dir: [{}] in COS", f);
String folderPath = pathToKey(makeAbsolute(f));
if (!folderPath.endsWith(PATH_DELIMITER)) {
folderPath += PATH_DELIMITER;
}
store.storeEmptyFile(folderPath);
}
}
return true;
}View on GitHub (pinned to 2add963021)
Solutions
- Walk every ancestor of the reported path, find the entry that isFile(), and remove or relocate it.
- Serialize directory creation among concurrent writers or use a deterministic layout so collisions cannot occur.
- Retry mkdirs after cleanup.
Example fix
// before
fs.mkdirs(new Path('/etl/dt=2026/zone=cn')); // message names /etl/dt=2026/zone=cn, but conflict is at an ancestor
// after
for (Path a = new Path('/etl/dt=2026/zone=cn').getParent(); a != null; a = a.getParent()) {
if (fs.exists(a) && fs.getFileStatus(a).isFile()) { fs.delete(a, false); }
}
fs.mkdirs(new Path('/etl/dt=2026/zone=cn')); Defensive patterns
Strategy: validation
Validate before calling
for (Path anc = f.getParent(); anc != null && !anc.isRoot(); anc = anc.getParent()) {
if (fs.exists(anc) && fs.getFileStatus(anc).isFile()) {
throw new IllegalStateException('Ancestor is a file: ' + anc);
}
} Try / catch
try {
fs.mkdirs(f);
} catch (FileAlreadyExistsException e) {
// message names f, not the ancestor: walk parents to find the real file
for (Path a = f.getParent(); a != null; a = a.getParent()) {
if (fs.exists(a) && fs.getFileStatus(a).isFile()) { fs.delete(a, false); }
}
fs.mkdirs(f); // retry once
} Prevention
- Serialize directory creation among concurrent writers on shared prefixes
- Expect TOCTOU between validatePath and the recursive walk under concurrency
- Retry mkdirs once after clearing conflicting ancestors
When it happens
Trigger: fs.mkdirs reaching mkDirRecursively after validatePath passed, then hitting an existing file at an intermediate level; a concurrent writer creating a file at an ancestor between validatePath and the recursive walk (time-of-check/time-of-use window).
Common situations: Concurrent jobs creating conflicting layouts under the same prefix; retries after partial failures that left files at intermediate paths.
Related errors
- Can't make directory for path '%s', it is a file.
- Path is a file: {}
- Multipart upload incomplete: expected {} parts but got {}
- {} already exists
- Can not delete root path
AI-assisted analysis of apache/hadoop@2add963021 (2026-08-22).
Data as JSON: /api/errors/b1cbde5dc7ada290.
Report an issue: GitHub.