apache/dolphinscheduler · error · FileAlreadyExistsException

file: ${dstPath} already exists

Error message

file: ${dstPath} already exists

What it means

OssStorageOperator.upload throws FileAlreadyExistsException when the destination OSS key exists and overwrite=false. Unlike the OBS operator which throws ObsException, this one throws the JDK FileAlreadyExistsException.

Source

Thrown at dolphinscheduler-storage-plugin/dolphinscheduler-storage-oss/src/main/java/org/apache/dolphinscheduler/plugin/storage/oss/OssStorageOperator.java:196

    @Override
    public void copy(String srcPath, String dstPath, boolean deleteSource, boolean overwrite) {
        srcPath = transformAbsolutePathToOssKey(srcPath);
        dstPath = transformAbsolutePathToOssKey(dstPath);

        ossClient.copyObject(bucketName, srcPath, bucketName, dstPath);
        if (deleteSource) {
            ossClient.deleteObject(bucketName, srcPath);
        }
    }

    @SneakyThrows
    @Override
    public void upload(String srcFile, String dstPath, boolean deleteSource, boolean overwrite) {
        dstPath = transformAbsolutePathToOssKey(dstPath);
        if (ossClient.doesObjectExist(bucketName, dstPath)) {
            if (!overwrite) {
                throw new FileAlreadyExistsException("file: " + dstPath + " already exists");
            } else {
                ossClient.deleteObject(bucketName, dstPath);
            }

        }
        ossClient.putObject(bucketName, dstPath, new File(srcFile));
        if (deleteSource) {
            Files.delete(Paths.get(srcFile));
        }
    }

    @SneakyThrows
    @Override
    public List<String> fetchFileContent(String filePath, int skipLineNums, int limit) {
        filePath = transformAbsolutePathToOssKey(filePath);
        OSSObject ossObject = ossClient.getObject(bucketName, filePath);
        try (
                InputStreamReader inputStreamReader = new InputStreamReader(ossObject.getObjectContent());

View on GitHub (pinned to 02eac45a1b)

Solutions

  1. Pass overwrite=true to replace the existing object
  2. Delete the destination object before uploading
  3. Use a unique dstPath per run

Example fix

// before
storageOperator.upload(src, dst, false, false);
// after
if (storageOperator.existsStorageFile(dst)) {
    storageOperator.upload(src, dst, false, true);
} else {
    storageOperator.upload(src, dst, false, false);
}
Defensive patterns

Strategy: validation

Validate before calling

if (storageOperator.existsStorageFile(dstPath) && !overwrite) {
    throw new IllegalStateException("Refusing to upload to existing path " + dstPath);
}
storageOperator.upload(srcFile, dstPath, deleteSource, overwrite);

Try / catch

try {
    storageOperator.upload(src, dst, false, false);
} catch (FileAlreadyExistsException e) {
    log.warn("{} exists, retrying with overwrite", dst);
    storageOperator.upload(src, dst, false, true);
}

Prevention

When it happens

Trigger: Calling upload(srcFile, dstPath, deleteSource, false) where ossClient.doesObjectExist reports the dstPath key already exists.

Common situations: Repeated uploads to a fixed resource path without overwrite; leftover object from a failed prior run; two tasks uploading to the same destination concurrently.

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/30fd567611894558. Report an issue: GitHub.