apache/hadoop · error · IllegalArgumentException

Move destination must be different from source for %s.

Error message

Move destination must be different from source for %s.

What it means

During move validation, after the cross-bucket check, the code rejects pairs where source and destination are the same bucket AND the same object name, throwing IllegalArgumentException("Move destination must be different from source for %s."). A self-move is a no-op at best and a livelock at worst, so the API demands callers filter it themselves.

Source

Thrown at hadoop-cloud-storage-project/hadoop-gcp/src/main/java/org/apache/hadoop/fs/gs/GoogleCloudStorage.java:730

    for (Map.Entry<StorageResourceId, StorageResourceId> entry :
        sourceToDestinationObjectsMap.entrySet()) {
      StorageResourceId source = entry.getKey();
      StorageResourceId destination = entry.getValue();
      String srcBucketName = source.getBucketName();
      String dstBucketName = destination.getBucketName();
      // Avoid move across buckets.
      if (!srcBucketName.equals(dstBucketName)) {
        throw new UnsupportedOperationException(
            "This operation is not supported across two different buckets.");
      }
      checkArgument(
          !isNullOrEmpty(source.getObjectName()), "srcObjectName must not be null or empty");
      checkArgument(
          !isNullOrEmpty(destination.getObjectName()), "dstObjectName must not be null or empty");
      if (srcBucketName.equals(dstBucketName)
          && source.getObjectName().equals(destination.getObjectName())) {
        throw new IllegalArgumentException(
            String.format(
                "Move destination must be different from source for %s.",
                StringPaths.fromComponents(srcBucketName, source.getObjectName())));
      }
    }
  }

  void copy(Map<StorageResourceId, StorageResourceId> sourceToDestinationObjectsMap)
      throws IOException {
    validateCopyArguments(sourceToDestinationObjectsMap, this);

    if (sourceToDestinationObjectsMap.isEmpty()) {
      return;
    }

    for (Map.Entry<StorageResourceId, StorageResourceId> entry :
        sourceToDestinationObjectsMap.entrySet()) {
      StorageResourceId srcObject = entry.getKey();

View on GitHub (pinned to 2add963021)

Solutions

  1. Filter identity mappings before calling move: skip when src.equals(dst)
  2. Fix the destination-path computation so renames actually change the object name
  3. For fs.rename(path, path), short-circuit to success in calling code — it is a no-op

Example fix

// before
for (Map.Entry<StorageResourceId, StorageResourceId> e : moves.entrySet()) {
  gcs.moveObjects(...); // may contain src==dst -> IllegalArgumentException
}

// after
for (Map.Entry<StorageResourceId, StorageResourceId> e : moves.entrySet()) {
  if (!e.getKey().equals(e.getValue())) {
    gcs.moveObjects(...);
  }
}
Defensive patterns

Strategy: validation

Validate before calling

// Drop identity mappings before moving
Map<StorageResourceId, StorageResourceId> moves = ...;
moves.entrySet().removeIf(e -> e.getKey().equals(e.getValue()));
gcs.moveObjects(moves);

Prevention

When it happens

Trigger: Calling move/rename with src == dst (identical bucket and object name), e.g. fs.rename(path, path), or a bulk move map that includes identity entries — often produced by directory-rename code that maps a parent onto itself for root entries.

Common situations: Rename loops that compute destination by string replacement and produce the same path; task commit moving files into a directory they are already in; recursive directory moves that include the directory itself in the file list.

Related errors


AI-assisted analysis of apache/hadoop@2add963021 (2026-08-22). Data as JSON: /api/errors/5f8efae25ae18c52. Report an issue: GitHub.