{"record":{"id":"7eeeb6ea490d0486","repo":"apache/hadoop","slug":"it-is-not-allowed-to-rename-a-parent-directory-s","errorCode":null,"errorMessage":"It is not allowed to rename a parent directory: %s to its subdirectory: %s","messagePattern":"It is not allowed to rename a parent directory: (.+?) to its subdirectory: (.+?)","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"hadoop-cloud-storage-project/hadoop-cos/src/main/java/org/apache/hadoop/fs/cosn/CosNFileSystem.java","lineNumber":639,"sourceCode":"          + \"the same file or directory\");\n    }\n\n    // It is not allowed to rename a parent directory to its subdirectory\n    Path dstParentPath;\n    for (dstParentPath = dst.getParent();\n         null != dstParentPath && !src.equals(dstParentPath);\n         dstParentPath = dstParentPath.getParent()) {\n      // Recursively find the common parent path of the source and\n      // destination paths.\n      LOG.debug(\"Recursively find the common parent directory of the source \"\n              + \"and destination paths. The currently found parent path: {}\",\n          dstParentPath);\n    }\n\n    if (null != dstParentPath) {\n      LOG.debug(\"It is not allowed to rename a parent directory:[{}] \"\n          + \"to its subdirectory:[{}].\", src, dst);\n      throw new IOException(String.format(\n          \"It is not allowed to rename a parent directory: %s \"\n              + \"to its subdirectory: %s\", src, dst));\n    }\n\n    FileStatus dstFileStatus;\n    try {\n      dstFileStatus = this.getFileStatus(dst);\n\n      // The destination path exists and is a file,\n      // and the rename operation is not allowed.\n      if (dstFileStatus.isFile()) {\n        throw new FileAlreadyExistsException(String.format(\n            \"File: %s already exists\", dstFileStatus.getPath()));\n      } else {\n        // The destination path is an existing directory,\n        // and it is checked whether there is a file or directory\n        // with the same name as the source path under the destination path\n        dst = new Path(dst, src.getName());","sourceCodeStart":621,"sourceCodeEnd":657,"githubUrl":"https://github.com/apache/hadoop/blob/2add9630210752f88ceb1bb74eb65e37bf41da8e/hadoop-cloud-storage-project/hadoop-cos/src/main/java/org/apache/hadoop/fs/cosn/CosNFileSystem.java#L621-L657","documentation":"rename walks dst's parent chain; if src itself appears among dst's ancestors (dst lies inside src, e.g. rename('/a','/a/b/c')) it throws IOException. Moving a directory into its own subtree would create a cycle, so CosN rejects it before any destination-existence checks run. The loop terminates with dstParentPath non-null exactly when src is an ancestor of dst.","triggerScenarios":"fs.rename(new Path('/a'), new Path('/a/b/c')); archive/rollup jobs moving a date directory into a subdirectory of itself; destination built by appending a suffix under the source path (e.g. /logs into /logs/archive).","commonSituations":"Archive scripts computing destination as source path + suffix; misordered arguments in a move utility; log rotation moving a directory into its own archive subfolder.","solutions":["Choose a destination outside the source subtree (e.g. /archive/day instead of /data/day/archive when renaming /data/day).","If nesting is genuinely required, copy with FileUtil.copy(fs, src, fs, dst, true, conf) and then delete the source.","Validate before calling: walk dst's parents and fail fast if any equals src."],"exampleFix":"// before\nfs.rename(new Path('/data/day=22'), new Path('/data/day=22/archive')); // IOException\n\n// after\nfs.rename(new Path('/data/day=22'), new Path('/archive/day=22'));","handlingStrategy":"validation","validationCode":"for (Path anc = dst.getParent(); anc != null; anc = anc.getParent()) {\n  if (anc.equals(src)) {\n    throw new IllegalArgumentException('Destination lies inside source: ' + dst);\n  }\n}","typeGuard":null,"tryCatchPattern":"try {\n  fs.rename(src, dst);\n} catch (IOException e) {\n  if (e.getMessage() != null && e.getMessage().contains('subdirectory')) {\n    // pick a destination outside the subtree, or copy+delete\n    FileUtil.copy(fs, src, fs, outsideDst, true, conf);\n    fs.delete(src, true);\n  } else { throw e; }\n}","preventionTips":["Never build destinations by appending suffixes under the source path","Archive into a sibling or external prefix, not into the source subtree","Validate dst lineage against src before every directory rename"],"tags":["cosn","hadoop","rename","subdirectory","cycle-prevention"],"backgroundTag":"rename-into-own-subdirectory","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-22T20:17:22.307Z"}