{"record":{"id":"9c3357e59c117185","repo":"apache/cordova-android","slug":"target-path-already-exists","errorCode":null,"errorMessage":"\"${target_path}\" already exists!","messagePattern":"\"(.+?)\" already exists!","errorType":"validation","errorClass":"CordovaError","httpStatus":null,"severity":"error","filePath":"lib/pluginHandlers.js","lineNumber":233,"sourceCode":"    if (!isPathInside(real_path, real_plugin_path)) { throw new CordovaError('File \"' + src + '\" is located outside the plugin directory \"' + plugin_dir + '\"'); }\n\n    dest = path.resolve(project_dir, dest);\n\n    // check that dest path is located in project directory\n    if (!isPathInside(dest, project_dir)) { throw new CordovaError('Destination \"' + dest + '\" for source file \"' + src + '\" is located outside the project'); }\n\n    fs.mkdirSync(path.dirname(dest), { recursive: true });\n    if (link) {\n        symlinkFileOrDirTree(src, dest);\n    } else {\n        fs.cpSync(src, dest, { recursive: true });\n    }\n}\n\n// Same as copy file but throws error if target exists\nfunction copyNewFile (plugin_dir, src, project_dir, dest, link) {\n    const target_path = path.resolve(project_dir, dest);\n    if (fs.existsSync(target_path)) { throw new CordovaError('\"' + target_path + '\" already exists!'); }\n\n    copyFile(plugin_dir, src, project_dir, dest, !!link);\n}\n\nfunction symlinkFileOrDirTree (src, dest) {\n    if (fs.existsSync(dest)) {\n        fs.rmSync(dest, { recursive: true, force: true });\n    }\n\n    if (fs.statSync(src).isDirectory()) {\n        fs.mkdirSync(path.dirname(dest), { recursive: true });\n        fs.readdirSync(src).forEach(function (entry) {\n            symlinkFileOrDirTree(path.join(src, entry), path.join(dest, entry));\n        });\n    } else {\n        fs.symlinkSync(path.relative(fs.realpathSync(path.dirname(dest)), src), dest);\n    }\n}","sourceCodeStart":215,"sourceCodeEnd":251,"githubUrl":"https://github.com/apache/cordova-android/blob/7c1e190064e349ffa4bbc6ac37b77cd773e4dbd3/lib/pluginHandlers.js#L215-L251","documentation":"copyNewFile (used for source-file, framework, etc. unless --force) refuses to overwrite: if the resolved destination already exists on disk it throws. It prevents a plugin install from silently clobbering files that already exist in the Android project, which usually means the plugin (or an older version of it) was installed before and not fully removed.","triggerScenarios":"`cordova plugin add` for a plugin whose <source-file> target path already exists: e.g. plugin added twice, a previous uninstall left files behind, or two plugins shipping a file with the same target-dir and name. Not thrown for resource-file/asset (those use plain copyFile and overwrite) nor when options.force is set.","commonSituations":"Re-adding a plugin after a failed uninstall or manual surgery on platforms/; upgrading a plugin whose files changed location; two plugins bundling the same support library source file; stale platforms/ directory after switching branches.","solutions":["Remove the plugin cleanly first (`cordova plugin rm <id>`), delete any leftover target files it reports, then re-add","Regenerate the platform if state is uncertain: `cordova platform rm android && cordova platform add android`","Intentional overwrite? re-add with `cordova plugin add <id> --force` so copyFile is used instead of copyNewFile","For your own plugin, give shared/generic files a namespaced target path (e.g. target-dir includes your package name) to avoid collisions with other plugins"],"exampleFix":"# before\ncordova plugin add cordova-plugin-foo   # throws: file already exists\n\n# after\ncordova plugin rm cordova-plugin-foo\ncordova platform rm android && cordova platform add android\ncordova plugin add cordova-plugin-foo\n# or, to allow overwriting:\ncordova plugin add cordova-plugin-foo --force","handlingStrategy":"fallback","validationCode":"// pre-flight: check whether the plugin's source-file targets already exist\nconst fs = require('fs'); const path = require('path');\nconst projectDir = 'platforms/android';\nconst exists = fs.existsSync(path.resolve(projectDir, targetDirAttr, path.basename(srcAttr)));\n// if exists, choose --force or clean up leftovers before installing","typeGuard":null,"tryCatchPattern":"try { await cordova.plugin('add', p); } catch (e) {\n  if (/already exists!/.test(e.message)) { /* rm plugin / regenerate platform, or re-add with --force */ }\n}","preventionTips":["Always `cordova plugin rm` before manually touching plugin files","When a plugin fails mid-install, remove it fully before retrying","Namespace target-dir with your package name to avoid collisions","Use `--force` only when overwriting is intentional"],"tags":["cordova","cordova-android","plugin-install","file-exists","conflict"],"backgroundTag":"file-already-exists","analyzedSha":"7c1e190064e349ffa4bbc6ac37b77cd773e4dbd3","analyzedAt":"2026-08-22T04:57:58.868Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}