apache/hadoop · error · IllegalArgumentException
Copy destination must be different from source for %s.
Error message
Copy destination must be different from source for %s.
What it means
GoogleCloudStorage.copy throws IllegalArgumentException when source and destination resolve to the identical bucket AND identical object name. The connector treats a self-copy as a caller bug rather than a no-op or a way to mint a new generation. The check runs after the bucket location/storage-class checks and the non-empty object-name checkArguments.
Source
Thrown at hadoop-cloud-storage-project/hadoop-gcp/src/main/java/org/apache/hadoop/fs/gs/GoogleCloudStorage.java:854
// TODO: Restrict this only when copy-with-rewrite is enabled
if (!srcBucketInfo.getLocation().equals(dstBucketInfo.getLocation())) {
throw new UnsupportedOperationException(
"This operation is not supported across two different storage locations.");
}
if (!srcBucketInfo.getStorageClass().equals(dstBucketInfo.getStorageClass())) {
throw new UnsupportedOperationException(
"This operation is not supported across two different storage classes.");
}
}
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(
"Copy destination must be different from source for %s.",
StringPaths.fromComponents(srcBucketName, source.getObjectName())));
}
}
}
private static GoogleCloudStorageItemInfo getGoogleCloudStorageItemInfo(
GoogleCloudStorage gcsImpl,
Map<StorageResourceId, GoogleCloudStorageItemInfo> bucketInfoCache,
StorageResourceId resourceId)
throws IOException {
GoogleCloudStorageItemInfo storageItemInfo = bucketInfoCache.get(resourceId);
if (storageItemInfo != null) {
return storageItemInfo;
}
storageItemInfo = gcsImpl.getItemInfo(resourceId);
bucketInfoCache.put(resourceId, storageItemInfo);View on GitHub (pinned to 2add963021)
Solutions
- Guard the call: skip copy when src and dst bucket+object names are equal (usually a no-op for the caller's intent).
- Fix the code constructing the destination so it can never equal the source.
- If you genuinely need a fresh generation of the same object, copy to a temporary name then copy/delete back, or call the storage client's CopyRequest directly.
Example fix
// before
gcs.copy(srcId, dstId); // dstId.equals(srcId) -> IllegalArgumentException
// after
if (!srcId.equals(dstId)) {
gcs.copy(srcId, dstId);
} Defensive patterns
Strategy: validation
Validate before calling
if (srcId.getBucketName().equals(dstId.getBucketName())
&& srcId.getObjectName().equals(dstId.getObjectName())) {
return; // self-copy is a no-op for this caller
}
gcs.copy(srcId, dstId); Prevention
- Derive destinations from sources only through transformations guaranteed to change the name.
- Add unit tests asserting src != dst on every copy call path.
- Log src/dst ids at call sites so mis-built arguments are visible in logs.
When it happens
Trigger: gcs.copy(source, destination) where srcBucketName.equals(dstBucketName) && source.getObjectName().equals(destination.getObjectName()) — e.g. rename fallbacks that compute dst from src, dedup logic, or scripts that pass the same path twice.
Common situations: Templated jobs where destination is derived from the source string and ends up identical; 'copy to backup' scripts invoked with the same src/dst arguments; rename implementations that fall back to copy without an equality guard.
Related errors
- Bucket not found: %s
- Path must be absolute: " + path
- Bucket doesn't match for source '%s' and destination '%s'!
- copy(%s->%s) failed.
- This operation is not supported across two different storage
AI-assisted analysis of apache/hadoop@2add963021 (2026-08-22).
Data as JSON: /api/errors/b632dba92b271e49.
Report an issue: GitHub.