apache/cordova-android · error · CordovaError

"${src}" not found!

Error message

"${src}" not found!

What it means

copyFile resolves the src attribute against the plugin directory and throws this CordovaError when fs.existsSync fails. It means the file the plugin.xml advertises (source-file, resource-file, asset, header-file, etc.) is not present in the fetched plugin copy, so nothing can be copied into the Android project.

Source

Thrown at lib/pluginHandlers.js:210

module.exports.getInstaller = function (type) {
    if (handlers[type] && handlers[type].install) {
        return handlers[type].install;
    }

    events.emit('verbose', '<' + type + '> is not supported for android plugins');
};

module.exports.getUninstaller = function (type) {
    if (handlers[type] && handlers[type].uninstall) {
        return handlers[type].uninstall;
    }

    events.emit('verbose', '<' + type + '> is not supported for android plugins');
};

function copyFile (plugin_dir, src, project_dir, dest, link) {
    src = path.resolve(plugin_dir, src);
    if (!fs.existsSync(src)) throw new CordovaError('"' + src + '" not found!');

    // check that src path is inside plugin directory
    const real_path = fs.realpathSync(src);
    const real_plugin_path = fs.realpathSync(plugin_dir);
    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 });
    }
}

View on GitHub (pinned to 7c1e190064)

Solutions

  1. Open the error-quoted absolute path: verify the file exists in the fetched plugin (node_modules or plugins/<id>) and fix the src path in plugin.xml to match exactly
  2. Check filename casing character-by-character if it works on macOS/Windows but fails on Linux
  3. If packaging dropped the file, fix .npmignore/.gitignore and publish a new plugin version (`npm publish`), then update the dependency

Example fix

<!-- before: file lives at src/android/Foo.java -->
<source-file src="Foo.java" target-dir="src/com/example" />

<!-- after -->
<source-file src="src/android/Foo.java" target-dir="src/com/example" />
Defensive patterns

Strategy: validation

Validate before calling

// verify every src referenced by plugin.xml exists in the package before publishing
const fs = require('fs'); const path = require('path'); const { execSync } = require('child_process');
execSync(`grep -oP '(?<=src=")[^"]+' plugin.xml`).toString().split('\n')
  .filter(s => !/^[a-z]+:/.test(s)) // skip gradle coordinates / URLs
  .forEach(s => { if (!fs.existsSync(path.join(pluginRoot, s))) throw new Error(`src missing on disk: ${s}`); });

Try / catch

try { await cordova.plugin('add', p); } catch (e) {
  if (/not found!/.test(e.message)) { /* the quoted path shows exactly which file is absent; check packaging/case/path */ }
}

Prevention

When it happens

Trigger: `cordova plugin add` for an element like <source-file src="src/android/Foo.java" .../> where that path does not exist under the plugin root. Common concrete causes: file excluded from the npm package, wrong relative path depth, or case mismatch (Foo.java vs foo.java) on case-sensitive filesystems (Linux CI).

Common situations: .gitignore/.npmignore accidentally excluding src files so the published tarball is incomplete; plugin refactored but plugin.xml paths not updated; macOS dev works, Linux CI fails because of filename case; src written as absolute path or with ../ segments.

Related errors


AI-assisted analysis of apache/cordova-android@7c1e190064 (2026-08-22). Data as JSON: /api/errors/bc7f0b3e52531f35. Report an issue: GitHub.