How to fix Error: EEXIST: file already exists, copyfile (COPYFILE_EXCL flag set) in Node.js

Node.jsINTERMEDIATEMEDIUMUpdated Mar 30, 2026ยท 131 views

This error occurs when fs.copyFile() is called with the COPYFILE_EXCL flag and the destination file already exists. The COPYFILE_EXCL flag is a safety mechanism that prevents overwriting existing files, causing the operation to fail if the destination path is occupied.

Quick fix

Fixes EEXIST

const fs = require('fs').promises;

async function copyFile(src, dest) {
  // Without COPYFILE_EXCL - will overwrite if dest exists
  await fs.copyFile(src, dest);
  console.log('File copied successfully');
}

// Or with callback style
const fs = require('fs');
fs.copyFile('source.txt', 'destination.txt', (err) => {
  if (err) throw err;
  console.log('Copy completed');
});
  1. Remove the COPYFILE_EXCL flag if overwriting is acceptable
  2. Delete the destination file before copying with COPYFILE_EXCL
  3. Catch and handle the EEXIST error specifically
  4. Create destination files with unique names
node.js โ€” error
const fs = require('fs').promises;
async function copyFile(src, dest) {
// Without COPYFILE_EXCL - will overwrite if dest exists
await fs.copyFile(src, dest);
console.log('File copied successfully');
}
// Or with callback style
const fs = require('fs');
fs.copyFile('source.txt', 'destination.txt', (err) => {
if (err) throw err;
console.log('Copy completed');
});
Error: EEXIST: file already exists, copyfile (COPYFILE_EXCL flag set)

What this error means

The EEXIST error with fs.copyFile and COPYFILE_EXCL indicates that a file copy operation failed because the destination file already exists and you explicitly specified that it should not be overwritten. The COPYFILE_EXCL flag (constants.COPYFILE_EXCL) is a safety feature in Node.js that makes fs.copyFile() fail rather than silently overwrite the destination. This is useful when you want to ensure you never accidentally replace an existing file. However, this strict behavior means you must handle the case where the destination already exists. This error is particularly common in scenarios like file uploads where the same filename might be copied multiple times, data migration scripts that run repeatedly, or backup systems where destination files may already exist from previous operations.

Typical symptoms

  • fs.copyFile() throws EEXIST error when using COPYFILE_EXCL flag
  • Error message shows "file already exists, copyfile (COPYFILE_EXCL flag set)"
  • File upload or copy operations fail on subsequent runs with the same destination
  • Scripts that copy files halt unexpectedly when destination file exists
  • Application crashes when attempting to copy files to existing locations
  • Automated backup or sync processes fail partway through due to existing destination files

Common causes

  1. Using COPYFILE_EXCL flag when the destination file already exists
  2. Running file copy operations multiple times without removing the destination file first
  3. Missing cleanup between test runs or batch operations
  4. Not checking if a destination file exists before copying with COPYFILE_EXCL
  5. File upload systems receiving the same filename multiple times
  6. Concurrent copy operations targeting the same destination file
  7. Scripts that should create copies with unique names but reuse the same path

How to fix "Error: EEXIST: file already exists, copyfile (COPYFILE_EXCL flag set)"

1Remove the COPYFILE_EXCL flag if overwriting is acceptable

The simplest solution is to use fs.copyFile() without the COPYFILE_EXCL flag. This allows the operation to overwrite existing files:

javascript
const fs = require('fs').promises;

async function copyFile(src, dest) {
  // Without COPYFILE_EXCL - will overwrite if dest exists
  await fs.copyFile(src, dest);
  console.log('File copied successfully');
}

// Or with callback style
const fs = require('fs');
fs.copyFile('source.txt', 'destination.txt', (err) => {
  if (err) throw err;
  console.log('Copy completed');
});

Use this approach when you don't care if the destination file already exists or should be replaced.

2Delete the destination file before copying with COPYFILE_EXCL

If you need to use COPYFILE_EXCL for safety, remove the destination file first if it exists:

javascript
const fs = require('fs').promises;
const { COPYFILE_EXCL } = require('fs').constants;

async function safeCopyFile(src, dest) {
  try {
    // Try to remove destination if it exists
    await fs.unlink(dest);
  } catch (err) {
    if (err.code !== 'ENOENT') {
      // If error is not "file not found", re-throw
      throw err;
    }
    // File doesn't exist, which is fine
  }

  // Now copy with COPYFILE_EXCL flag
  await fs.copyFile(src, dest, COPYFILE_EXCL);
  console.log('File copied with safety flag');
}

This pattern ensures the destination is clean before copying, so COPYFILE_EXCL won't conflict with existing files.

3Catch and handle the EEXIST error specifically

If you want different behavior when the file already exists, catch the EEXIST error and handle it appropriately:

javascript
const fs = require('fs').promises;
const { COPYFILE_EXCL } = require('fs').constants;

async function copyFileWithFallback(src, dest) {
  try {
    // Try to copy with safety flag
    await fs.copyFile(src, dest, COPYFILE_EXCL);
    console.log('File copied (destination did not exist)');
  } catch (err) {
    if (err.code === 'EEXIST') {
      console.log('Destination already exists, using existing file');
      // Could also skip, log a warning, or copy to alternate location
    } else {
      throw err; // Re-throw other errors like EACCES or EIO
    }
  }
}

// Or with synchronous code
const fs = require('fs');
try {
  fs.copyFileSync(src, dest, fs.constants.COPYFILE_EXCL);
} catch (err) {
  if (err.code === 'EEXIST') {
    console.log('File already exists');
  } else {
    throw err;
  }
}

This approach is useful when you want to gracefully handle existing files without crashing.

4Create destination files with unique names

If you need to preserve both the source and any existing destination, generate unique filenames:

javascript
const fs = require('fs').promises;
const path = require('path');
const { COPYFILE_EXCL } = require('fs').constants;

async function copyFileWithUniqueName(src, destDir) {
  const baseName = path.basename(src);
  const ext = path.extname(baseName);
  const nameWithoutExt = path.basename(baseName, ext);

  let destPath = path.join(destDir, baseName);
  let counter = 1;

  // Keep incrementing filename until we find an available name
  while (true) {
    try {
      await fs.copyFile(src, destPath, COPYFILE_EXCL);
      console.log(`Copied to: ${destPath}`);
      return destPath;
    } catch (err) {
      if (err.code === 'EEXIST') {
        // Try next numbered version
        destPath = path.join(
          destDir,
          `${nameWithoutExt} (${counter})${ext}`
        );
        counter++;
      } else {
        throw err;
      }
    }
  }
}

// Usage
await copyFileWithUniqueName('upload.txt', './uploads');
// Creates: uploads/upload.txt, uploads/upload (1).txt, uploads/upload (2).txt, etc.

This pattern is common in file upload systems where multiple files might have the same name.

5Check if destination exists before copying

Use fs.access() or fs.stat() to check for the destination file before attempting to copy with COPYFILE_EXCL:

javascript
const fs = require('fs').promises;
const { COPYFILE_EXCL } = require('fs').constants;

async function copyFileIfNotExists(src, dest) {
  try {
    // Check if destination exists
    await fs.access(dest);
    console.log('Destination already exists, skipping copy');
    return false;
  } catch (err) {
    if (err.code === 'ENOENT') {
      // Destination doesn't exist, safe to copy
      await fs.copyFile(src, dest, COPYFILE_EXCL);
      console.log('File copied successfully');
      return true;
    } else {
      throw err; // Other errors like EACCES
    }
  }
}

// Or using fs.existsSync for synchronous operations
function copyFileIfNotExistsSync(src, dest) {
  if (fs.existsSync(dest)) {
    console.log('Destination already exists, skipping');
    return false;
  }
  fs.copyFileSync(src, dest, fs.constants.COPYFILE_EXCL);
  console.log('File copied');
  return true;
}

Note: There's a small race condition between checking and copying. In concurrent scenarios, use error handling (step 3) instead.

6Implement robust file copy logic for batch operations

For scripts that copy multiple files or run repeatedly, implement comprehensive error handling:

javascript
const fs = require('fs').promises;
const path = require('path');
const { COPYFILE_EXCL } = require('fs').constants;

async function robustFileCopy(src, dest, options = {}) {
  const {
    overwrite = false,
    createUnique = false,
    maxRetries = 3,
  } = options;

  // Strategy 1: Overwrite existing file
  if (overwrite) {
    try {
      await fs.unlink(dest);
    } catch (err) {
      if (err.code !== 'ENOENT') throw err;
    }
    await fs.copyFile(src, dest);
    return { success: true, path: dest };
  }

  // Strategy 2: Create unique filename if exists
  if (createUnique) {
    let finalDest = dest;
    let counter = 0;
    while (counter < 100) {
      try {
        await fs.copyFile(src, finalDest, COPYFILE_EXCL);
        return { success: true, path: finalDest };
      } catch (err) {
        if (err.code === 'EEXIST') {
          const ext = path.extname(dest);
          const dir = path.dirname(dest);
          const base = path.basename(dest, ext);
          finalDest = path.join(dir, `${base}-${++counter}${ext}`);
        } else {
          throw err;
        }
      }
    }
    throw new Error('Could not find unique filename after 100 attempts');
  }

  // Strategy 3: Fail if exists (default with COPYFILE_EXCL)
  for (let attempt = 0; attempt < maxRetries; attempt++) {
    try {
      await fs.copyFile(src, dest, COPYFILE_EXCL);
      return { success: true, path: dest };
    } catch (err) {
      if (err.code === 'EEXIST' && attempt === maxRetries - 1) {
        return { success: false, error: 'Destination already exists', code: 'EEXIST' };
      }
      if (err.code !== 'EEXIST') throw err;
      // Retry with delay for transient issues
      await new Promise(resolve => setTimeout(resolve, 100));
    }
  }
}

// Usage examples
await robustFileCopy('source.txt', 'dest.txt');
await robustFileCopy('source.txt', 'dest.txt', { overwrite: true });
await robustFileCopy('source.txt', 'dest.txt', { createUnique: true });

This flexible approach handles different scenarios in a single function.

Advanced notes

Understanding fs.constants.COPYFILE_EXCL: This flag makes fs.copyFile() fail rather than silently overwrite. It's equivalent to opening a file with the O_EXCL flag in C/C++. Use it when you absolutely need to prevent accidental file overwrites and want the operation to fail rather than silently lose data.

Performance considerations: Removing a file before copying (step 2) has filesystem overhead. If you're copying many files, consider the performance impact and whether overwriting is acceptable instead.

Concurrent file operations: In multi-threaded or worker-based scenarios, even checking and then copying creates a race condition. Always rely on the atomic error handling (step 3) rather than pre-checks.

Stream-based copying for large files: For very large files, fs.copyFile() uses efficient kernel-level copy-on-write on supported systems (Linux 4.5+, macOS). However, for more control over large file operations, consider using fs.createReadStream() and fs.createWriteStream().

File permissions and ownership: fs.copyFile() copies file content and mode bits but NOT ownership or extended attributes. The copied file will be owned by the process user. Use fs.chown() separately if you need to match ownership.

Windows and NTFS considerations: On Windows, fs.copyFile() may behave differently with special files (NTFS alternate streams). Test thoroughly on Windows if your application targets it.

Docker and containerized environments: When copying files between volumes or mounts, EEXIST errors may indicate permission issues or inconsistent filesystem state. Verify volume mounting and permissions before assuming the file actually exists.

Backup and disaster recovery: If building a backup system, use the unique naming strategy (step 4) to preserve previous versions. Never blindly overwrite backups.

Testing implications: Unit tests that copy files should clean up destination files in teardown hooks to avoid EEXIST errors on subsequent test runs. Use temporary directories for isolated test files.

Frequently asked questions

What does "EEXIST" mean?
copyFile and COPYFILE_EXCL indicates that a file copy operation failed because the destination file already exists and you explicitly specified that it should not be overwritten. copyFile() fail rather than silently overwrite the destination. This is useful when you want to ensure you never accidentally replace an existing file.
How do I fix "EEXIST"?
This error occurs when fs.copyFile() is called with the COPYFILE_EXCL flag and the destination file already exists. The COPYFILE_EXCL flag is a safety mechanism that prevents overwriting existing files, causing the operation to fail if the destination path is occupied.
What causes "EEXIST"?
Using COPYFILE_EXCL flag when the destination file already exists Running file copy operations multiple times without removing the destination file first Missing cleanup between test runs or batch operations
Is the "EEXIST" error serious?
It is a medium-severity error โ€” more of a blocker than a risk. The steps above resolve it.

Official resources & further reading