bmad-code-org/BMAD-METHOD · error · Error

${dest} already exists

Error message

${dest} already exists

What it means

Thrown by the native fs copy() helper when overwrite is false, options.errorOnExist is true, and the destination file already exists. This mirrors fs-extra semantics: a non-overwriting copy that is configured to error (rather than silently skip) refuses to clobber an existing file.

Source

Thrown at tools/installer/fs-native.js:36

  await fsp.mkdir(dir, { recursive: true });
}

async function remove(p) {
  await fsp.rm(p, { recursive: true, force: true });
}

async function copy(src, dest, options = {}) {
  const filterFn = options.filter;
  const overwrite = options.overwrite !== false;
  const srcStat = await fsp.stat(src);

  if (srcStat.isFile()) {
    if (filterFn && !(await filterFn(src, dest))) return;
    await fsp.mkdir(path.dirname(dest), { recursive: true });
    if (!overwrite) {
      try {
        await fsp.access(dest);
        if (options.errorOnExist) throw new Error(`${dest} already exists`);
        return;
      } catch (error) {
        if (error.message.includes('already exists')) throw error;
      }
    }
    await fsp.copyFile(src, dest);
    return;
  }

  if (srcStat.isDirectory()) {
    if (filterFn && !(await filterFn(src, dest))) return;
    await fsp.mkdir(dest, { recursive: true });
    const entries = await fsp.readdir(src, { withFileTypes: true });
    for (const entry of entries) {
      await copy(path.join(src, entry.name), path.join(dest, entry.name), options);
    }
  }
}

View on GitHub (pinned to b70486b9bd)

Solutions

  1. Delete or move the existing destination before copying.
  2. Pass overwrite:true if clobbering is acceptable.
  3. Pass errorOnExist:false to silently skip existing files instead of throwing.

Example fix

// before
await fs.copy(src, dest, { overwrite: false, errorOnExist: true });

// after (allow overwrite)
await fs.copy(src, dest, { overwrite: true });
Defensive patterns

Strategy: validation

Validate before calling

if (options.errorOnExist && !(options.overwrite ?? true) && (await fs.pathExists(dest))) {
  // remove dest first, or switch off errorOnExist
}

Try / catch

try {
  await fs.copy(src, dest, { overwrite: false, errorOnExist: true });
} catch (error) {
  if (error.message.endsWith('already exists')) { /* dest collision; handle */ }
  throw error;
}

Prevention

When it happens

Trigger: fs.copy(src, dest, { overwrite: false, errorOnExist: true }) and `dest` already exists. The default FileOps.copyDirectory sets errorOnExist:false, so this only fires when a caller explicitly opts into errorOnExist.

Common situations: A caller intentionally requests fail-on-exist semantics (e.g. to detect collisions) and the destination path is already present from a prior run.

Related errors


AI-assisted analysis of bmad-code-org/BMAD-METHOD@b70486b9bd (2026-08-13). Data as JSON: /api/errors/24ceb49df05fda75. Report an issue: GitHub.