{"record":{"id":"4dcc9e81cee3ee72","repo":"apache/hadoop","slug":"destination-parent-is-not-a-directory","errorCode":null,"errorMessage":"destination parent [{}] is not a directory","messagePattern":"destination parent \\[(.+?)\\] is not a directory","errorType":"exception","errorClass":"ParentNotDirectoryException","httpStatus":null,"severity":"error","filePath":"hadoop-cloud-storage-project/hadoop-huaweicloud/src/main/java/org/apache/hadoop/fs/obs/OBSObjectBucketUtils.java","lineNumber":195,"sourceCode":"\n    if (src.getParent() != dst.getParent()) {\n      // deleteUnnecessaryFakeDirectories(dst.getParent());\n      createFakeDirectoryIfNecessary(owner, src.getParent());\n    }\n\n    return true;\n  }\n\n  private static void checkDestinationParent(final OBSFileSystem owner,\n      final Path src,\n      final Path dst) throws IOException {\n    Path parent = dst.getParent();\n    if (!OBSCommonUtils.pathToKey(owner, parent).isEmpty()) {\n      try {\n        FileStatus dstParentStatus = owner.getFileStatus(\n            dst.getParent());\n        if (!dstParentStatus.isDirectory()) {\n          throw new ParentNotDirectoryException(\n              \"destination parent [\" + dst.getParent()\n                  + \"] is not a directory\");\n        }\n      } catch (FileNotFoundException e2) {\n        throw new RenameFailedException(src, dst,\n            \"destination has no parent \");\n      }\n    }\n  }\n\n  /**\n   * Implement rename file.\n   *\n   * @param owner     OBS File System instance\n   * @param srcKey    source object key\n   * @param dstKey    destination object key\n   * @param srcStatus source object status\n   * @throws IOException any problem with rename operation","sourceCodeStart":177,"sourceCodeEnd":213,"githubUrl":"https://github.com/apache/hadoop/blob/2add9630210752f88ceb1bb74eb65e37bf41da8e/hadoop-cloud-storage-project/hadoop-huaweicloud/src/main/java/org/apache/hadoop/fs/obs/OBSObjectBucketUtils.java#L177-L213","documentation":"checkDestinationParent stats the parent of the rename destination after the destination itself was found missing. A parent that exists but is not a directory makes the rename invalid, so it throws Hadoop's ParentNotDirectoryException('destination parent [<parent>] is not a directory'). The check only runs when the parent key is non-empty, so the bucket root as parent is accepted.","triggerScenarios":"fs.rename(src, '/plainfile/out') where /plainfile is a regular file; writing output under a path component that was earlier created as a file (marker file, empty success file); partition layouts where a partition value exists as a file.","commonSituations":"A job or user created a zero-byte marker at the same name later used as a directory; mixed workloads sharing a prefix with inconsistent conventions; tools migrating data that flatten some components into files.","solutions":["Stat the destination parent with getFileStatus and require isDirectory() before renaming","Delete or relocate the file that occupies the parent path, then recreate the directory","Call fs.mkdirs(dst.getParent()) first; it fails fast if a file blocks any level of the chain"],"exampleFix":"// before\nfs.rename(src, new Path(\"/marker/out\")); // /marker is a file\n\n// after\nPath parent = new Path(\"/marker\");\nif (fs.exists(parent) && !fs.getFileStatus(parent).isDirectory()) {\n  fs.delete(parent, false);\n  fs.mkdirs(parent);\n}\nfs.rename(src, new Path(\"/marker/out\"));","handlingStrategy":"validation","validationCode":"Path parent = dst.getParent();\nif (parent != null && !parent.isRoot() && fs.exists(parent)\n    && !fs.getFileStatus(parent).isDirectory()) {\n  throw new ParentNotDirectoryException(\"Destination parent is a file: \" + parent);\n}","typeGuard":"static boolean parentIsDirectory(FileSystem fs, Path p) throws IOException {\n  Path parent = p.getParent();\n  return parent == null || parent.isRoot()\n      || !fs.exists(parent) || fs.getFileStatus(parent).isDirectory();\n}","tryCatchPattern":"try {\n  fs.rename(src, dst);\n} catch (ParentNotDirectoryException e) {\n  // a file occupies an ancestor of dst: remove it or pick another layout\n}","preventionTips":["Reserve name spaces: a name is either always a file or always a directory","Validate the parent chain with mkdirs(dst.getParent()) before moves","Audit marker files that share names with later directories"],"tags":["hadoop","obs","rename","parent-directory","path-hierarchy"],"backgroundTag":"parent-not-a-directory","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-22T20:17:22.307Z"}