apache/cordova-android · error · CordovaError
" " already exists!
Error message
"${target_path}" already exists! What it means
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.
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
Example fix
# before cordova plugin add cordova-plugin-foo # throws: file already exists # after cordova plugin rm cordova-plugin-foo cordova platform rm android && cordova platform add android cordova plugin add cordova-plugin-foo # or, to allow overwriting: cordova plugin add cordova-plugin-foo --force
Defensive patterns
Strategy: fallback
Validate before calling
// pre-flight: check whether the plugin's source-file targets already exist
const fs = require('fs'); const path = require('path');
const projectDir = 'platforms/android';
const exists = fs.existsSync(path.resolve(projectDir, targetDirAttr, path.basename(srcAttr)));
// if exists, choose --force or clean up leftovers before installing Try / catch
try { await cordova.plugin('add', p); } catch (e) {
if (/already exists!/.test(e.message)) { /* rm plugin / regenerate platform, or re-add with --force */ }
} Prevention
- 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
When it happens
Trigger: `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.
Common situations: 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.
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
- Could not find any APKs to deploy
- Could not find target matching
- Destination " " for source file " " is located outside the…
- Do not perform IO operations on the UI thread. Use…
- File " " is located outside the plugin directory
AI-assisted analysis of apache/cordova-android@7c1e190064 (2026-08-22).
Data as JSON: /api/errors/9c3357e59c117185.
Report an issue: GitHub.
Appendix: source
Thrown at lib/pluginHandlers.js:233
if (!isPathInside(real_path, real_plugin_path)) { throw new CordovaError('File "' + src + '" is located outside the plugin directory "' + plugin_dir + '"'); }
dest = path.resolve(project_dir, dest);
// check that dest path is located in project directory
if (!isPathInside(dest, project_dir)) { throw new CordovaError('Destination "' + dest + '" for source file "' + src + '" is located outside the project'); }
fs.mkdirSync(path.dirname(dest), { recursive: true });
if (link) {
symlinkFileOrDirTree(src, dest);
} else {
fs.cpSync(src, dest, { recursive: true });
}
}
// Same as copy file but throws error if target exists
function copyNewFile (plugin_dir, src, project_dir, dest, link) {
const target_path = path.resolve(project_dir, dest);
if (fs.existsSync(target_path)) { throw new CordovaError('"' + target_path + '" already exists!'); }
copyFile(plugin_dir, src, project_dir, dest, !!link);
}
function symlinkFileOrDirTree (src, dest) {
if (fs.existsSync(dest)) {
fs.rmSync(dest, { recursive: true, force: true });
}
if (fs.statSync(src).isDirectory()) {
fs.mkdirSync(path.dirname(dest), { recursive: true });
fs.readdirSync(src).forEach(function (entry) {
symlinkFileOrDirTree(path.join(src, entry), path.join(dest, entry));
});
} else {
fs.symlinkSync(path.relative(fs.realpathSync(path.dirname(dest)), src), dest);
}
}View on GitHub (pinned to 7c1e190064)