{"record":{"id":"bc7f0b3e52531f35","repo":"apache/cordova-android","slug":"src-not-found","errorCode":null,"errorMessage":"\"${src}\" not found!","messagePattern":"\"(.+?)\" not found!","errorType":"validation","errorClass":"CordovaError","httpStatus":null,"severity":"error","filePath":"lib/pluginHandlers.js","lineNumber":210,"sourceCode":"module.exports.getInstaller = function (type) {\n    if (handlers[type] && handlers[type].install) {\n        return handlers[type].install;\n    }\n\n    events.emit('verbose', '<' + type + '> is not supported for android plugins');\n};\n\nmodule.exports.getUninstaller = function (type) {\n    if (handlers[type] && handlers[type].uninstall) {\n        return handlers[type].uninstall;\n    }\n\n    events.emit('verbose', '<' + type + '> is not supported for android plugins');\n};\n\nfunction copyFile (plugin_dir, src, project_dir, dest, link) {\n    src = path.resolve(plugin_dir, src);\n    if (!fs.existsSync(src)) throw new CordovaError('\"' + src + '\" not found!');\n\n    // check that src path is inside plugin directory\n    const real_path = fs.realpathSync(src);\n    const real_plugin_path = fs.realpathSync(plugin_dir);\n    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}","sourceCodeStart":192,"sourceCodeEnd":228,"githubUrl":"https://github.com/apache/cordova-android/blob/7c1e190064e349ffa4bbc6ac37b77cd773e4dbd3/lib/pluginHandlers.js#L192-L228","documentation":"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.","triggerScenarios":"`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).","commonSituations":".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.","solutions":["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","Check filename casing character-by-character if it works on macOS/Windows but fails on Linux","If packaging dropped the file, fix .npmignore/.gitignore and publish a new plugin version (`npm publish`), then update the dependency"],"exampleFix":"<!-- before: file lives at src/android/Foo.java -->\n<source-file src=\"Foo.java\" target-dir=\"src/com/example\" />\n\n<!-- after -->\n<source-file src=\"src/android/Foo.java\" target-dir=\"src/com/example\" />","handlingStrategy":"validation","validationCode":"// verify every src referenced by plugin.xml exists in the package before publishing\nconst fs = require('fs'); const path = require('path'); const { execSync } = require('child_process');\nexecSync(`grep -oP '(?<=src=\")[^\"]+' plugin.xml`).toString().split('\\n')\n  .filter(s => !/^[a-z]+:/.test(s)) // skip gradle coordinates / URLs\n  .forEach(s => { if (!fs.existsSync(path.join(pluginRoot, s))) throw new Error(`src missing on disk: ${s}`); });","typeGuard":null,"tryCatchPattern":"try { await cordova.plugin('add', p); } catch (e) {\n  if (/not found!/.test(e.message)) { /* the quoted path shows exactly which file is absent; check packaging/case/path */ }\n}","preventionTips":["Publish plugins with `npm pack --dry-run` first and confirm all referenced files are in the tarball","Develop on a case-sensitive filesystem (or enable it) to catch filename-case bugs","Keep plugin.xml paths relative to the plugin root without ../"],"tags":["cordova","cordova-android","plugin-xml","file-not-found","install"],"backgroundTag":"packaged-file-missing","analyzedSha":"7c1e190064e349ffa4bbc6ac37b77cd773e4dbd3","analyzedAt":"2026-08-22T04:57:58.868Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}