apache/seatunnel · error · FileAlreadyExistsException

Destination path %s already exists

Error message

Destination path %s already exists

What it means

rename() refuses to overwrite: after absolutizing paths (and resolving a directory destination by appending the source name), it checks the final destination via exists() and throws FileAlreadyExistsException 'Destination path %s already exists' when a file/dir is already there.

Source

Thrown at seatunnel-connectors-v2/connector-file/connector-file-ftp/src/main/java/org/apache/seatunnel/connectors/seatunnel/file/ftp/system/SeaTunnelFTPFileSystem.java:842

     * @param src src
     * @param dst dst
     * @return result
     * @throws IOException IOException
     */
    private boolean rename(FTPClient client, Path src, Path dst) throws IOException {
        Path workDir = new Path(client.printWorkingDirectory());
        Path absoluteSrc = makeAbsolute(workDir, src);
        Path absoluteDst = makeAbsolute(workDir, dst);
        if (!exists(client, absoluteSrc)) {
            throw new FileNotFoundException("Source path " + src + " does not exist");
        }
        if (isDirectory(absoluteDst)) {
            // destination is a directory: rename goes underneath it with the
            // source name
            absoluteDst = new Path(absoluteDst, absoluteSrc.getName());
        }
        if (exists(client, absoluteDst)) {
            throw new FileAlreadyExistsException("Destination path " + dst + " already exists");
        }
        if (isParentOf(absoluteSrc, absoluteDst)) {
            throw new IOException(
                    "Cannot rename " + absoluteSrc + " under itself" + " : " + absoluteDst);
        }
        String from = absoluteSrc.toUri().getPath();
        String to = absoluteDst.toUri().getPath();
        return client.rename(from, to);
    }

    @Override
    public Path getWorkingDirectory() {
        // Return home directory always since we do not maintain state.
        return getHomeDirectory();
    }

    @Override
    public Path getHomeDirectory() {

View on GitHub (pinned to cf67b549a7)

Solutions

  1. Delete or move the existing destination file before renaming (or have the job clean its output directory on start)
  2. Configure schema_save_mode/data_save_mode (e.g. CREATE_SCHEMA_WHEN_NOT_EXIST with a unique output path per run)
  3. Use unique destination names per execution (timestamp/partition suffix) to avoid collisions
  4. Serialize job runs so two jobs don't target the same output file concurrently

Example fix

// before
fs.rename(new Path("/tmp/part-0"), new Path("/data/part-0")); // may already exist
// after
Path dst = new Path("/data/part-0");
if (fs.exists(dst)) {
    fs.delete(dst, false);
}
fs.rename(new Path("/tmp/part-0"), dst);
Defensive patterns

Strategy: validation

Validate before calling

// Java: delete-or-assert before rename
Path dst = new Path("/data/part-0");
if (ftpFileSystem.exists(dst)) {
    ftpFileSystem.delete(dst, false); // or fail fast
}

Try / catch

try {
    fs.rename(src, dst);
} catch (FileAlreadyExistsException e) {
    logger.error("Destination exists: {} — clean up or use unique names", dst);
}

Prevention

When it happens

Trigger: rename(client, src, dst) called where exists(client, absoluteDst) is true after dst is normalized — including the case where dst is an existing directory and absoluteSrc.getName() already exists inside it.

Common situations: Re-running a job without cleanup so the previous run's output already sits at the destination; two concurrent jobs writing the same target file; sink save_mode set to something that doesn't pre-clean files; committing a temp file to a name that already exists.

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/seatunnel@cf67b549a7 (2026-09-10). Data as JSON: /api/errors/965d209b5dddaf63. Report an issue: GitHub.