kestra-io/kestra · error · FileAlreadyExistsException

File {} already exist

Error message

File {} already exist

What it means

Thrown by `LocalWorkingDir.putFile` when the target file already exists AND the caller selected `FileExistComportment.FAIL`. The other comportments are OVERWRITE (logs and replaces), WARN (logs and skips), and IGNORE (silent skip). Thrown as `java.nio.file.FileAlreadyExistsException` with the resolved path in the message.

Source

Thrown at core/src/main/java/io/kestra/core/runners/LocalWorkingDir.java:208

     **/
    @Override
    public Path putFile(Path path, InputStream inputStream, FileExistComportment comportment) throws IOException {
        if (path == null) {
            throw new IllegalArgumentException("Cannot create a working directory file with a null path");
        }
        if (inputStream == null) {
            throw new IllegalArgumentException("Cannot create a working directory file with an empty inputStream");
        }
        Path newFilePath = this.resolve(path);
        Files.createDirectories(newFilePath.getParent());

        if (Files.exists(newFilePath)) {
            switch (comportment) {
                case OVERWRITE -> {
                    log.info("File {} already exist. It will be overwritten", newFilePath);
                    copyFile(inputStream, newFilePath);
                }
                case FAIL -> throw new FileAlreadyExistsException("File " + newFilePath + " already exist");
                case WARN -> log.warn("File {} already exist. It will be ignore", newFilePath);
                case IGNORE -> {
                }
            }
        } else {
            Files.createFile(newFilePath);
            copyFile(inputStream, newFilePath);
        }

        return newFilePath;
    }

    private static void copyFile(InputStream inputStream, Path path) throws IOException {
        try (inputStream) {
            Files.copy(inputStream, path, REPLACE_EXISTING);
        }
    }

View on GitHub (pinned to 823fada927)

Solutions

  1. Use `FileExistComportment.OVERWRITE` if replacement is intended.
  2. Generate a unique filename per write (append an index or `IdUtils.create()`).
  3. Keep `FAIL` and delete the existing file first, or check existence and branch.
  4. Use `createTempFile()` for guaranteed-unique scratch files.

Example fix

// before
workingDir.putFile(Path.of("out.csv"), in, FileExistComportment.FAIL);

// after — overwrite is fine
workingDir.putFile(Path.of("out.csv"), in, FileExistComportment.OVERWRITE);
// or unique name
workingDir.putFile(Path.of("out-" + i + ".csv"), in, FileExistComportment.FAIL);
Defensive patterns

Strategy: validation

Validate before calling

Path target = path;
if (Files.exists(workingDir.resolve(target)) && comportment == FileExistComportment.FAIL) {
    // either delete first or choose a unique name
    target = Path.of(target + "." + IdUtils.create());
}
return workingDir.putFile(target, in, comportment);

Try / catch

try {
    workingDir.putFile(path, in, FileExistComportment.FAIL);
} catch (FileAlreadyExistsException e) {
    // collision detected — choose a unique name and retry once
    workingDir.putFile(Path.of(path + "." + IdUtils.create()), in, FileExistComportment.FAIL);
}

Prevention

When it happens

Trigger: Calling `workingDir.putFile(path, in, FileExistComportment.FAIL)` when `path` already resolves to an existing file — e.g. a task writing the same filename twice in one execution, or a filename collision from a loop iteration.

Common situations: A ForEach loop whose iterations write to a fixed filename; re-running logic that re-creates the same file; a download task that overwrites a previously-created file when FAIL was chosen to detect collisions.

Related errors


AI-assisted analysis of kestra-io/kestra@823fada927 (2026-08-14). Data as JSON: /api/errors/c556d617bd5aa498. Report an issue: GitHub.