{"record":{"id":"3247741aa01e5e96","repo":"apache/hadoop","slug":"is-not-a-directory","errorCode":null,"errorMessage":"{} is not a directory","messagePattern":"(.+?) 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/OBSPosixBucketUtils.java","lineNumber":160,"sourceCode":"                  + \"file or directory: {}\", dstPath);\n          return true;\n        } else {\n          LOG.error(\"rename: failed to rename \" + src + \" to \"\n              + dstPath\n              + \" because destination exists\");\n          return false;\n        }\n      }\n    } catch (FileNotFoundException e) {\n      // if destination does not exist, do not change the\n      // destination key, and just do rename.\n      LOG.debug(\"rename: dest [{}] does not exist\", dstPath);\n    } catch (FileConflictException e) {\n      Path parent = dstPath.getParent();\n      if (!OBSCommonUtils.pathToKey(owner, parent).isEmpty()) {\n        FileStatus dstParentStatus = owner.getFileStatus(parent);\n        if (!dstParentStatus.isDirectory()) {\n          throw new ParentNotDirectoryException(\n              parent + \" is not a directory\");\n        }\n      }\n    }\n\n    if (dstKey.startsWith(srcKey) && (dstKey.equals(srcKey)\n        || dstKey.charAt(srcKey.length()) == Path.SEPARATOR_CHAR)) {\n      LOG.error(\"rename: dest [{}] cannot be a descendant of src [{}]\",\n          dstPath, src);\n      return false;\n    }\n\n    return innerFsRenameWithRetry(owner, src, dstPath, srcKey, dstKey);\n  }\n\n  private static boolean innerFsRenameWithRetry(final OBSFileSystem owner,\n      final Path src,\n      final Path dst, final String srcKey, final String dstKey)","sourceCodeStart":142,"sourceCodeEnd":178,"githubUrl":"https://github.com/apache/hadoop/blob/2add9630210752f88ceb1bb74eb65e37bf41da8e/hadoop-cloud-storage-project/hadoop-huaweicloud/src/main/java/org/apache/hadoop/fs/obs/OBSPosixBucketUtils.java#L142-L178","documentation":"In the POSIX-protocol rename path, an ObsException with code CONFLICT is caught and explained: the code stats the destination parent and throws ParentNotDirectoryException('<parent> is not a directory') when that parent exists as a file. Hadoop requires every destination ancestor to be a directory, and the OBS POSIX rename refused the operation for exactly that reason.","triggerScenarios":"rename to /plainfile/out where /plainfile is a regular object; target paths where one component was previously written as a file; mixing marker-file conventions with directory-based layouts in one POSIX bucket.","commonSituations":"File and folder name collisions in POSIX-layout buckets; tools that create zero-byte markers and later treat the same names as directories; data restored or copied with a flattened structure.","solutions":["Validate that every ancestor of the destination is a directory before rename","Delete the file blocking the path, then create the directory chain with mkdirs","Adopt a layout rule that never reuses a file name as a directory component"],"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(\"Parent is a file: \" + parent);\n}","typeGuard":"static boolean isDirectoryPath(FileSystem fs, Path p) throws IOException {\n  return !fs.exists(p) || fs.getFileStatus(p).isDirectory();\n}","tryCatchPattern":"try {\n  fs.rename(src, dst);\n} catch (ParentNotDirectoryException e) {\n  // an ancestor of dst exists as a file: delete it or choose another layout\n}","preventionTips":["Enforce one naming convention: a component is either a file or a directory, never both","Check the destination parent chain before POSIX renames","Clean marker files before introducing directory layouts with the same names"],"tags":["hadoop","obs","posix","rename","parent-directory"],"backgroundTag":"parent-not-a-directory","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-22T20:17:22.307Z"}