apache/cassandra · error · RuntimeException

File already exists, can't move the file there

Error message

File %s already exists, can't move the file there

What it means

moveAndOpenSSTable() verifies that the target DATA file does not already exist before moving components. If newDescriptor's -Data.db file is already present, moving would overwrite existing data, so it logs and throws a RuntimeException naming the existing file.

Solutions

  1. Delete or rename the pre-existing target file if it is a stale leftover from a failed move
  2. Skip SSTables whose target descriptor already exists (idempotent import logic)
  3. Use unique generation/UUIDs for new descriptors so retries never collide
  4. Check the destination directory before running imports (ls the data dir for conflicting xx-Data.db files)

Example fix

// before: blindly moving over possibly existing files
Files.move(oldData, newData);
// after: guard against existing target
if (Files.exists(newData)) {
    Files.delete(newData); // or skip
}
Files.move(oldData, newData);
Defensive patterns

Strategy: validation

Validate before calling

// pre-check the target
if (newDesc.fileFor(Components.DATA).exists()) {
    // stale leftover or duplicate: delete or skip
}

Try / catch

try { SSTableReader.moveAndOpenSSTable(cfs, oldDesc, newDesc, comps, false); }
catch (RuntimeException e) {
    if (e.getMessage().contains("already exists, can't move the file there")) {
        logger.warn("Target exists, cleaning stale file {}", newDesc.fileFor(Components.DATA));
        // delete stale file and retry once
    } else throw e;
}

Prevention

When it happens

Trigger: Calling moveAndOpenSSTable where a file with the exact new descriptor (generation/UUID) already exists in the destination directory — e.g. re-importing the same SSTable set, or a partially completed previous move that left the data file behind.

Common situations: Retried sstable import jobs after a failed run; restoring backups into a directory that already contains the SSTables; concurrent imports generating the same target generation.

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/cassandra@88fd0f6a0e (2026-09-10). Data as JSON: /api/errors/3f007dc010c1b58d. Report an issue: GitHub.

Appendix: source

Thrown at src/java/org/apache/cassandra/io/sstable/format/SSTableReader.java:1885

    {
        if (!oldDescriptor.isCompatible())
            throw new RuntimeException(String.format("Can't open incompatible SSTable! Current version %s, found file: %s",
                                                     oldDescriptor.getFormat().getLatestVersion(),
                                                     oldDescriptor));

        boolean isLive = cfs.getLiveSSTables().stream().anyMatch(r -> r.descriptor.equals(newDescriptor)
                                                                      || r.descriptor.equals(oldDescriptor));
        if (isLive)
        {
            String message = String.format("Can't move and open a file that is already in use in the table %s -> %s", oldDescriptor, newDescriptor);
            logger.error(message);
            throw new RuntimeException(message);
        }
        if (newDescriptor.fileFor(Components.DATA).exists())
        {
            String msg = String.format("File %s already exists, can't move the file there", newDescriptor.fileFor(Components.DATA));
            logger.error(msg);
            throw new RuntimeException(msg);
        }

        if (copyData)
        {
            try
            {
                logger.info("Hardlinking new SSTable {} to {}", oldDescriptor, newDescriptor);
                hardlink(oldDescriptor, newDescriptor, components);
            }
            catch (FSWriteError ex)
            {
                logger.warn("Unable to hardlink new SSTable {} to {}, falling back to copying", oldDescriptor, newDescriptor, ex);
                copy(oldDescriptor, newDescriptor, components);
            }
        }
        else
        {
            logger.info("Moving new SSTable {} to {}", oldDescriptor, newDescriptor);

View on GitHub (pinned to 88fd0f6a0e)