{"record":{"id":"5acaaf464fdda424","repo":"apache/hadoop","slug":"can-t-make-directory-for-path-s-since-it-is-a-fil","errorCode":null,"errorMessage":"Can't make directory for path %s since it is a file.","messagePattern":"Can't make directory for path (.+?) since it is a file\\.","errorType":"exception","errorClass":"ParentNotDirectoryException","httpStatus":null,"severity":"error","filePath":"hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/ftp/FTPFileSystem.java","lineNumber":606,"sourceCode":"   * the overhead of opening/closing a TCP connection.\n   */\n  private boolean mkdirs(FTPClient client, Path file, FsPermission permission)\n      throws IOException {\n    boolean created = true;\n    Path workDir = new Path(client.printWorkingDirectory());\n    Path absolute = makeAbsolute(workDir, file);\n    String pathName = absolute.getName();\n    if (!exists(client, absolute)) {\n      Path parent = absolute.getParent();\n      created = (parent == null || mkdirs(client, parent, FsPermission\n          .getDirDefault()));\n      if (created) {\n        String parentDir = parent.toUri().getPath();\n        client.changeWorkingDirectory(parentDir);\n        created = created && client.makeDirectory(pathName);\n      }\n    } else if (isFile(client, absolute)) {\n      throw new ParentNotDirectoryException(String.format(\n          \"Can't make directory for path %s since it is a file.\", absolute));\n    }\n    return created;\n  }\n\n  /**\n   * Convenience method, so that we don't open a new connection when using this\n   * method from within another method. Otherwise every API invocation incurs\n   * the overhead of opening/closing a TCP connection.\n   */\n  private boolean isFile(FTPClient client, Path file) {\n    try {\n      return getFileStatus(client, file).isFile();\n    } catch (FileNotFoundException e) {\n      return false; // file does not exist\n    } catch (IOException ioe) {\n      throw new FTPException(\"File check failed\", ioe);\n    }","sourceCodeStart":588,"sourceCodeEnd":624,"githubUrl":"https://github.com/apache/hadoop/blob/2add9630210752f88ceb1bb74eb65e37bf41da8e/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/ftp/FTPFileSystem.java#L588-L624","documentation":"mkdirs() first checks whether the target exists; if it exists and is a regular file, creating a directory there is impossible and ParentNotDirectoryException is thrown — the standard Hadoop signal for 'a path component that must be a directory is a file'. Here the conflict is the target path itself.","triggerScenarios":"fs.mkdirs(path) where path already exists as a file; checkpoint/restart directories whose path was previously an output file; create-then-mkdirs ordering bugs in job setup.","commonSituations":"Reusing one path for different artifact types between runs; logic changes that turn a file path into a directory path; incomplete cleanup after a failed run leaves a file where a directory is now expected.","solutions":["Remove the conflicting file first: if (fs.exists(p) && fs.getFileStatus(p).isFile()) fs.delete(p, false)","Use distinct paths for file and directory artifacts instead of reusing the same string","Catch ParentNotDirectoryException to fail with a message naming the conflicting path"],"exampleFix":"// before\nfs.mkdirs(new Path(\"/data/out\")); // /data/out exists as a file\n// ParentNotDirectoryException\n\n// after\nPath p = new Path(\"/data/out\");\nif (fs.exists(p) && fs.getFileStatus(p).isFile()) {\n  fs.delete(p, false);\n}\nfs.mkdirs(p);","handlingStrategy":"validation","validationCode":"if (fs.exists(dir) && fs.getFileStatus(dir).isFile()) {\n  fs.delete(dir, false); // clear the file conflicting with the directory path\n}\nboolean ok = fs.mkdirs(dir);","typeGuard":"static boolean isFreeForDirectory(FileSystem fs, Path p) throws IOException {\n  return !fs.exists(p) || fs.getFileStatus(p).isDirectory();\n}","tryCatchPattern":"try {\n  fs.mkdirs(dir);\n} catch (ParentNotDirectoryException e) {\n  // a file occupies the path: surface which path conflicted instead of a generic failure\n  throw new IOException(\"Path conflicts with an existing file: \" + dir, e);\n}","preventionTips":["Never reuse one path string for both a file and a directory artifact","Check exists() + isFile() before mkdirs when paths come from configuration","Clean stale artifacts from previous runs during job setup"],"tags":["ftp","mkdirs","parent-not-directory"],"backgroundTag":"parent-not-directory","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-23T01:17:44.959Z"}