{"record":{"id":"24ceb49df05fda75","repo":"bmad-code-org/BMAD-METHOD","slug":"dest-already-exists","errorCode":null,"errorMessage":"${dest} already exists","messagePattern":"(.+?) already exists","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"tools/installer/fs-native.js","lineNumber":36,"sourceCode":"  await fsp.mkdir(dir, { recursive: true });\n}\n\nasync function remove(p) {\n  await fsp.rm(p, { recursive: true, force: true });\n}\n\nasync function copy(src, dest, options = {}) {\n  const filterFn = options.filter;\n  const overwrite = options.overwrite !== false;\n  const srcStat = await fsp.stat(src);\n\n  if (srcStat.isFile()) {\n    if (filterFn && !(await filterFn(src, dest))) return;\n    await fsp.mkdir(path.dirname(dest), { recursive: true });\n    if (!overwrite) {\n      try {\n        await fsp.access(dest);\n        if (options.errorOnExist) throw new Error(`${dest} already exists`);\n        return;\n      } catch (error) {\n        if (error.message.includes('already exists')) throw error;\n      }\n    }\n    await fsp.copyFile(src, dest);\n    return;\n  }\n\n  if (srcStat.isDirectory()) {\n    if (filterFn && !(await filterFn(src, dest))) return;\n    await fsp.mkdir(dest, { recursive: true });\n    const entries = await fsp.readdir(src, { withFileTypes: true });\n    for (const entry of entries) {\n      await copy(path.join(src, entry.name), path.join(dest, entry.name), options);\n    }\n  }\n}","sourceCodeStart":18,"sourceCodeEnd":54,"githubUrl":"https://github.com/bmad-code-org/BMAD-METHOD/blob/b70486b9bdcb0a404d329e2a763b57964e7f1360/tools/installer/fs-native.js#L18-L54","documentation":"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.","triggerScenarios":"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.","commonSituations":"A caller intentionally requests fail-on-exist semantics (e.g. to detect collisions) and the destination path is already present from a prior run.","solutions":["Delete or move the existing destination before copying.","Pass overwrite:true if clobbering is acceptable.","Pass errorOnExist:false to silently skip existing files instead of throwing."],"exampleFix":"// before\nawait fs.copy(src, dest, { overwrite: false, errorOnExist: true });\n\n// after (allow overwrite)\nawait fs.copy(src, dest, { overwrite: true });","handlingStrategy":"validation","validationCode":"if (options.errorOnExist && !(options.overwrite ?? true) && (await fs.pathExists(dest))) {\n  // remove dest first, or switch off errorOnExist\n}","typeGuard":null,"tryCatchPattern":"try {\n  await fs.copy(src, dest, { overwrite: false, errorOnExist: true });\n} catch (error) {\n  if (error.message.endsWith('already exists')) { /* dest collision; handle */ }\n  throw error;\n}","preventionTips":["Only set errorOnExist when you genuinely want collisions to fail.","Clean the destination tree before non-overwriting copies."],"tags":["filesystem","copy","conflict"],"backgroundTag":null,"analyzedSha":"b70486b9bdcb0a404d329e2a763b57964e7f1360","analyzedAt":"2026-08-13T01:21:12.247Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}