{"record":{"id":"b09a9a64f117e989","repo":"apache/hadoop","slug":"rename-dir-to-self-is-forbidden","errorCode":null,"errorMessage":"Rename dir to self is forbidden","messagePattern":"Rename dir to self is forbidden","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"hadoop-cloud-storage-project/hadoop-gcp/src/main/java/org/apache/hadoop/fs/gs/GoogleCloudStorageFileSystem.java","lineNumber":591,"sourceCode":"    // After applying the rules, we will be left with 2 paths such that:\n    // -- either both are files or both are directories\n    // -- src exists and dst leaf does not exist\n    if (srcInfo.isDirectory()) {\n      // -- if src is a directory\n      //    -- dst is an existing file => disallowed\n      //    -- dst is a directory => rename the directory.\n\n      // The first case (dst is an existing file) is already checked earlier.\n      // If the destination path looks like a file, make it look like a\n      // directory path. This is because users often type 'mv foo bar'\n      // rather than 'mv foo bar/'.\n      if (!dstInfo.isDirectory()) {\n        dst = UriPaths.toDirectory(dst);\n      }\n\n      // Throw if renaming directory to self - this is forbidden\n      if (src.equals(dst)) {\n        throw new IOException(\"Rename dir to self is forbidden\");\n      }\n\n      URI dstRelativeToSrc = src.relativize(dst);\n      // Throw if dst URI relative to src is not equal to dst,\n      // because this means that src is a parent directory of dst\n      // and src cannot be \"renamed\" to its subdirectory\n      if (!dstRelativeToSrc.equals(dst)) {\n        throw new IOException(\"Rename to subdir is forbidden\");\n      }\n\n      if (dstInfo.exists()) {\n        dst =\n            dst.equals(GCSROOT)\n                ? UriPaths.fromStringPathComponents(\n                srcItemName, /* objectName= */ null, /* allowEmptyObjectName= */ true)\n                : UriPaths.toDirectory(dst.resolve(srcItemName));\n      }\n    } else {","sourceCodeStart":573,"sourceCodeEnd":609,"githubUrl":"https://github.com/apache/hadoop/blob/2add9630210752f88ceb1bb74eb65e37bf41da8e/hadoop-cloud-storage-project/hadoop-gcp/src/main/java/org/apache/hadoop/fs/gs/GoogleCloudStorageFileSystem.java#L573-L609","documentation":"In getDstUri, when the source is a directory the destination is normalized to directory form (UriPaths.toDirectory, adding the trailing '/') and then compared to src; if they are equal the rename is rejected because renaming a directory to itself is a forbidden no-op rather than a silent success.","triggerScenarios":"rename(gs://b/foo, gs://b/foo) or rename(gs://b/foo, gs://b/foo/) - the trailing slash is normalized away, making dst equal src. Any dst differing from src only by a trailing '/'.","commonSituations":"Shell-style 'mv dir dir/' habits encoded into scripts; destination built programmatically from the source path plus an optional separator; copy-pasted paths that accidentally reuse the source as destination.","solutions":["Skip the rename when the normalized source and destination are equal (compare UriPaths.toDirectory of both).","Choose a genuinely different destination directory name.","When constructing destinations, never derive dst purely from src plus formatting."],"exampleFix":"// before\nPath src = new Path(\"gs://bucket/foo\");\nPath dst = new Path(\"gs://bucket/foo/\"); // normalized to src -> forbidden\nfs.rename(src, dst);\n\n// after\nURI s = UriPaths.toDirectory(src.toUri());\nURI d = UriPaths.toDirectory(dst.toUri());\nif (!s.equals(d)) {\n  fs.rename(src, dst);\n}","handlingStrategy":"validation","validationCode":"URI srcDir = UriPaths.toDirectory(src.toUri());\nURI dstDir = UriPaths.toDirectory(dst.toUri());\nif (!srcDir.equals(dstDir)) {\n  fs.rename(src, dst);\n}","typeGuard":null,"tryCatchPattern":"catch IOException with message equals(\"Rename dir to self is forbidden\") - treat as a no-op success or fix destination construction; do not retry.","preventionTips":["Normalize both sides (trailing '/') before comparing src and dst in rename wrappers.","Avoid building destinations from the source path plus optional formatting characters."],"tags":["rename","gcs","hadoop","directories","validation"],"backgroundTag":"rename-to-self","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-23T01:17:44.959Z"}