{"record":{"id":"6a01252304ea9443","repo":"apache/hadoop","slug":"moving-object-from-bucket-s-to-s-is-not-supp","errorCode":null,"errorMessage":"Moving object from bucket '%s' to '%s' is not supported","messagePattern":"Moving object from bucket '(.+?)' to '(.+?)' is not supported","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"hadoop-cloud-storage-project/hadoop-gcp/src/main/java/org/apache/hadoop/fs/gs/GoogleCloudStorageFileSystem.java","lineNumber":500,"sourceCode":"            dst, /* allowEmptyObjectName= */ true, /* generationId= */ 0L);\n    if (srcResourceId.getBucketName().equals(dstResourceId.getBucketName())) {\n      // First, move all items except marker items\n      moveInternal(srcToDstItemNames);\n      // Finally, move marker items (if any) to mark rename operation success\n      moveInternal(srcToDstMarkerItemNames);\n\n      if (srcInfo.getItemInfo().isBucket()) {\n        deleteBucket(Collections.singletonList(srcInfo));\n      } else {\n        // If src is a directory then srcItemInfos does not contain its own name,\n        // we delete item separately in the list.\n        deleteObjects(Collections.singletonList(srcInfo));\n      }\n      return;\n    }\n\n    // TODO: Add support for across bucket moves\n    throw new UnsupportedOperationException(String.format(\n        \"Moving object from bucket '%s' to '%s' is not supported\",\n        srcResourceId.getBucketName(),\n        dstResourceId.getBucketName()));\n  }\n\n  List<FileInfo> listFileInfoForPrefix(URI prefix, ListFileOptions listOptions)\n      throws IOException {\n    LOG.trace(\"listAllFileInfoForPrefix(prefix: {})\", prefix);\n    StorageResourceId prefixId = getPrefixId(prefix);\n    List<GoogleCloudStorageItemInfo> itemInfos =\n        gcs.listDirectoryRecursive(prefixId.getBucketName(), prefixId.getObjectName());\n    List<FileInfo> fileInfos = FileInfo.fromItemInfos(itemInfos);\n    fileInfos.sort(FILE_INFO_PATH_COMPARATOR);\n    return fileInfos;\n  }\n\n  /** Moves items in given map that maps source items to destination items. */\n  private void moveInternal(Map<FileInfo, URI> srcToDstItemNames) throws IOException {","sourceCodeStart":482,"sourceCodeEnd":518,"githubUrl":"https://github.com/apache/hadoop/blob/2add9630210752f88ceb1bb74eb65e37bf41da8e/hadoop-cloud-storage-project/hadoop-gcp/src/main/java/org/apache/hadoop/fs/gs/GoogleCloudStorageFileSystem.java#L482-L518","documentation":"rename only supports moves within a single bucket. After the same-bucket branches (including bucket-root handling) fall through, differing src/dst buckets produce UnsupportedOperationException — the source carries a TODO to add across-bucket moves. Cross-bucket transfer at the GoogleCloudStorage.copy layer additionally requires equal bucket location and storage class.","triggerScenarios":"GHFS/GoogleCloudStorageFileSystem rename from gs://bucket-a/... to gs://bucket-b/... for any non-bucket-root item — e.g. a job 'moving' outputs to another bucket via rename.","commonSituations":"Pipelines ported from HDFS where cross-directory rename is free; multi-bucket layouts expecting transparent moves; staging-to-publish workflows across buckets.","solutions":["Replace the rename with copy + delete: GoogleCloudStorage.copy (requires same location and storage class) followed by source deletion.","For bulk data use DistCp (update/delete semantics) or Storage Transfer Service instead of per-file rename.","Restructure the job to write directly into the destination bucket so no move is needed."],"exampleFix":"// before\nfs.rename(URI.create(\"gs://a/f\"), URI.create(\"gs://b/f\")); // UnsupportedOperationException\n\n// after: copy + delete within connector limits\ngcs.copy(new StorageResourceId(\"a\", \"f\"), new StorageResourceId(\"b\", \"f\"));\ngcs.deleteObjects(List.of(new StorageResourceId(\"a\", \"f\")));","handlingStrategy":"fallback","validationCode":"if (!src.getBucket().equals(dst.getBucket())) {\n  // connector cannot rename across buckets: copy + delete instead\n  gcs.copy(new StorageResourceId(src.getBucket(), src.getObject()),\n           new StorageResourceId(dst.getBucket(), dst.getObject()));\n  gcs.deleteObjects(List.of(new StorageResourceId(src.getBucket(), src.getObject())));\n} else {\n  fs.rename(src, dst);\n}","typeGuard":null,"tryCatchPattern":"catch (UnsupportedOperationException e) {\n  if (e.getMessage().contains(\"not supported\")) { /* switch to copy+delete or distcp */ } else throw e; }","preventionTips":["Never rely on rename for cross-bucket moves in GCS-backed filesystems.","Keep copy source/destination buckets matched on location and storage class so the fallback copy works.","For large moves, plan DistCp or Storage Transfer Service rather than per-file copy+delete."],"tags":["gcs","rename","cross-bucket","unsupported-operation"],"backgroundTag":"cross-bucket-rename-unsupported","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-22T20:17:22.307Z"}