apache/beam · error · UnsupportedOperationException
Skipping dest existence is only supported within a bucket.
Error message
Skipping dest existence is only supported within a bucket.
What it means
Thrown by GcsUtilV1 when copying with ignoreExistingDest=true (skip if destination exists) while source and destination are in different GCS buckets. The skip-if-exists optimization relies on a same-bucket existence check via generation match, so cross-bucket copies with this flag are rejected as unsupported.
Source
Thrown at sdks/java/extensions/google-cloud-platform-core/src/main/java/org/apache/beam/sdk/extensions/gcp/util/GcsUtilV1.java:1270
Iterable<String> srcFilenames,
Iterable<String> destFilenames,
boolean deleteSource,
boolean ignoreMissingSource,
boolean ignoreExistingDest)
throws IOException {
List<String> srcList = Lists.newArrayList(srcFilenames);
List<String> destList = Lists.newArrayList(destFilenames);
checkArgument(
srcList.size() == destList.size(),
"Number of source files %s must equal number of destination files %s",
srcList.size(),
destList.size());
LinkedList<RewriteOp> rewrites = Lists.newLinkedList();
for (int i = 0; i < srcList.size(); i++) {
final GcsPath sourcePath = GcsPath.fromUri(srcList.get(i));
final GcsPath destPath = GcsPath.fromUri(destList.get(i));
if (ignoreExistingDest && !sourcePath.getBucket().equals(destPath.getBucket())) {
throw new UnsupportedOperationException(
"Skipping dest existence is only supported within a bucket.");
}
rewrites.addLast(new RewriteOp(sourcePath, destPath, deleteSource, ignoreMissingSource));
}
return rewrites;
}
List<BatchInterface> makeRewriteBatches(LinkedList<RewriteOp> rewrites) throws IOException {
List<BatchInterface> batches = new ArrayList<>();
@Nullable BatchInterface opBatch = null;
boolean useSeparateRewriteDataBatch = this.rewriteDataOpBatchLimit != MAX_REQUESTS_PER_BATCH;
Iterator<RewriteOp> it = rewrites.iterator();
List<RewriteOp> deferredRewriteDataOps = new ArrayList<>();
while (it.hasNext()) {
RewriteOp rewrite = it.next();
if (!rewrite.getReadyToEnqueue()) {
it.remove();
continue;View on GitHub (pinned to 12126d8942)
Solutions
- Copy within the same bucket when using the ignore-existing-dest strategy.
- Drop the ignore/skip strategy for cross-bucket copies and handle FileAlreadyExistsException explicitly.
- Use OverwriteStrategy/OVERWRITE semantics if overwriting destinations is acceptable.
- Pre-check destination existence yourself and filter the copy list before calling.
Example fix
// before
options.copy(StandardCopyOption.IGNORE_EXISTING ...) cross-bucket
// after: same-bucket only, or fall back to overwrite
if (!src.getBucket().equals(dst.getBucket())) {
fs.copy(src, dst, StandardReplaceOptions.OVERWRITE /* or pre-check */);
} Defensive patterns
Strategy: validation
Validate before calling
boolean sameBucket = srcs.stream()
.map(URI::toString)
.noneMatch(s -> !GcsPath.fromUri(s).getBucket()
.equals(GcsPath.fromUri(dstFor(s)).getBucket()));
if (ignoreExistingDest && !sameBucket) {
// switch strategy or restrict to same-bucket copies
} Try / catch
try {
copyWithSkip(...);
} catch (UnsupportedOperationException e) {
if (e.getMessage().contains("Skipping dest existence")) {
copyWithOverwrite(...); // cross-bucket fallback
}
} Prevention
- Only use skip-if-exists strategies for same-bucket copies
- Design destination layouts so copy pairs stay within one bucket
- Pre-check destination existence yourself for cross-bucket flows
When it happens
Trigger: Calling fileCopyRewrite (or filesystem copy) with the skip-destination-exists strategy where srcList.get(i).getBucket() differs from destList.get(i).getBucket() for any pair.
Common situations: Configuring a Beam FileSystems.copy with IGNORE behavior for cross-bucket renames/archives; moving staged files from a staging bucket to a final bucket while assuming skip-if-exists is allowed.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- GcsSeekableByteChannels are read-only and cannot be truncate
- Runner does not support draining.
- Unknown DirectoryTreatment: " + directoryTreatment
- Support for move options is not yet implemented.
- %s is for internal use only and does not support case dispat
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/7a4503b3f5c27d0a.
Report an issue: GitHub.