apache/cordova-android · error · CordovaError

Required attribute "src" not specified in

Error message

Required attribute "src" not specified in <framework> element from plugin: ${plugin.id}

What it means

Thrown by cordova-android's framework install handler when a plugin's plugin.xml declares a <framework> element without a src attribute. On Android, <framework> pulls in a native library (an .aar, a Gradle project, or a system library) and src is the only way to locate it, so installation aborts before the project files are touched.

Solutions

  1. Open the plugin's plugin.xml and add src to every <framework> element under <platform name="android">, e.g. <framework src="libs/mylib.aar" custom="true"/>
  2. Check for misspelled attribute names (source= instead of src=) or the attribute accidentally placed on the parent <platform> element
  3. If the plugin comes from npm/GitHub, report the issue to the maintainer and use a forked/fixed version; republish with a version bump so dependents pick it up
  4. For local plugin development, re-run `cordova plugin add <path>` after fixing the XML to re-parse plugin.xml

Example fix

<!-- before -->
<platform name="android">
  <framework custom="true" />
</platform>

<!-- after -->
<platform name="android">
  <framework src="src/android/libs/mylib.aar" custom="true" />
</platform>
Defensive patterns

Strategy: validation

Validate before calling

// before installing a third-party plugin, lint its plugin.xml
const fs = require('fs');
const xml = fs.readFileSync('node_modules/<plugin>/plugin.xml', 'utf8');
if (/<framework(?![^>]*\bsrc=)[^>]*>/.test(xml.replace(/[\r\n]+/g, ' '))) {
  throw new Error('plugin has a <framework> element without src — fix before `cordova plugin add`');
}

Try / catch

try {
  await cordova.plugin('add', 'cordova-plugin-foo');
} catch (e) {
  if (e instanceof CordovaError && /Required attribute "src" not specified in <framework>/.test(e.message)) {
    // point the user at the plugin's plugin.xml <framework> elements
  }
}

Prevention

When it happens

Trigger: Running `cordova plugin add <plugin>` (or `cordova prepare android` after adding it) where plugin.xml contains <framework/>, <framework custom="true"/>, or <framework type="gradleReference"/> with no src attribute. The handler reads obj.src and throws CordovaError(generateAttributeError('src','framework',...)) when it is falsy.

Common situations: Hand-edited or template-generated plugin.xml that omits src; using the wrong attribute name (source=, href=, path=); copying a <framework> snippet from another plugin and stripping the attribute; plugin published to npm in this broken state.

Related errors


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

Appendix: source

Thrown at lib/pluginHandlers.js:75

        uninstall: function (obj, plugin, project, options) {
            const dest = path.join('app/libs', path.basename(obj.src));
            removeFileF(path.resolve(project.projectDir, dest));
        }
    },
    'resource-file': {
        install: function (obj, plugin, project, options) {
            const dest = path.join('app', 'src', 'main', obj.target);
            copyFile(plugin.dir, obj.src, project.projectDir, dest, !!(options && options.link));
        },
        uninstall: function (obj, plugin, project, options) {
            const dest = path.join('app', 'src', 'main', obj.target);
            removeFileF(path.resolve(project.projectDir, dest));
        }
    },
    framework: {
        install: function (obj, plugin, project, options) {
            const src = obj.src;
            if (!src) throw new CordovaError(generateAttributeError('src', 'framework', plugin.id));

            events.emit('verbose', 'Installing Android library: ' + src);
            const parentDir = obj.parent ? path.resolve(project.projectDir, obj.parent) : project.projectDir;
            let subDir;

            if (obj.custom) {
                const subRelativeDir = project.getCustomSubprojectRelativeDir(plugin.id, src);
                copyNewFile(plugin.dir, src, project.projectDir, subRelativeDir, !!(options && options.link));
                subDir = path.resolve(project.projectDir, subRelativeDir);
            } else {
                obj.type = 'sys';
                subDir = src;
            }

            if (obj.type === 'gradleReference') {
                project.addGradleReference(parentDir, subDir);
            } else if (obj.type === 'sys') {
                project.addSystemLibrary(parentDir, subDir);

View on GitHub (pinned to 7c1e190064)