apache/dolphinscheduler · error · FileAlreadyExistsException

file: ${dstPath} already exists

Error message

file: ${dstPath} already exists

What it means

GcsStorageOperator.upload throws FileAlreadyExistsException when the destination GCS key already exists and overwrite=false. The exists() check precedes the blob create call. With overwrite=true the blob is simply recreated with the new content.

Source

Thrown at dolphinscheduler-storage-plugin/dolphinscheduler-storage-gcs/src/main/java/org/apache/dolphinscheduler/plugin/storage/gcs/GcsStorageOperator.java:162

        BlobId target = BlobId.of(bucketName, dstPath);

        gcsStorage.copy(
                Storage.CopyRequest.newBuilder()
                        .setSource(source)
                        .setTarget(target)
                        .build());

        if (deleteSource) {
            gcsStorage.delete(source);
        }
    }

    @SneakyThrows
    @Override
    public void upload(String srcFile, String dstPath, boolean deleteSource, boolean overwrite) {
        dstPath = transformAbsolutePathToGcsKey(dstPath);
        if (exists(dstPath) && !overwrite) {
            throw new FileAlreadyExistsException("file: " + dstPath + " already exists");
        }
        BlobInfo blobInfo = BlobInfo.newBuilder(
                BlobId.of(bucketName, dstPath)).build();

        Path srcPath = Paths.get(srcFile);
        gcsStorage.create(blobInfo, Files.readAllBytes(srcPath));

        if (deleteSource) {
            Files.delete(srcPath);
        }
    }

    @SneakyThrows
    @Override
    public List<String> fetchFileContent(String filePath, int skipLineNums, int limit) {
        filePath = transformAbsolutePathToGcsKey(filePath);
        if (StringUtils.isBlank(filePath)) {
            log.error("file path:{} is blank", filePath);

View on GitHub (pinned to 02eac45a1b)

Solutions

  1. Pass overwrite=true to replace the blob
  2. Delete the existing blob first if it is safe
  3. Upload to a new/unique key to keep the old object

Example fix

// before
gcs.upload(localFile, resourceKey, false, false);
// after
gcs.upload(localFile, resourceKey, false, true);
Defensive patterns

Strategy: try-catch

Validate before calling

if (!overwrite && gcs.exists(dstKey)) { /* rename dst or confirm overwrite */ }

Try / catch

try {
    gcs.upload(src, dst, deleteSource, overwrite);
} catch (FileAlreadyExistsException e) {
    gcs.upload(src, dst, deleteSource, true);
}

Prevention

When it happens

Trigger: Calling upload(srcFile, dstPath, deleteSource, false) when a blob exists at the transformed dstPath key.

Common situations: Re-uploading a resource with overwrite disabled; concurrent uploads of the same resource key; retry after partial workflow failure leaving the blob in place.

Understand the failure class

Background: "already exists" / EEXIST / FileAlreadyExistsException: what the 'file already exists' error means and how to fix it — this error's family across 37 libraries.

Related errors


AI-assisted analysis of apache/dolphinscheduler@02eac45a1b (2026-09-06). Data as JSON: /api/errors/e8acbe6097cf69d0. Report an issue: GitHub.