{"record":{"id":"232f63a81ab4d691","repo":"apache/cordova-android","slug":"required-attribute-src-not-specified-in-framewo","errorCode":null,"errorMessage":"Required attribute \"src\" not specified in <framework> element from plugin: ${plugin.id}","messagePattern":"Required attribute \"src\" not specified in <framework> element from plugin: (.+?)","errorType":"validation","errorClass":"CordovaError","httpStatus":null,"severity":"error","filePath":"lib/pluginHandlers.js","lineNumber":75,"sourceCode":"        uninstall: function (obj, plugin, project, options) {\n            const dest = path.join('app/libs', path.basename(obj.src));\n            removeFileF(path.resolve(project.projectDir, dest));\n        }\n    },\n    'resource-file': {\n        install: function (obj, plugin, project, options) {\n            const dest = path.join('app', 'src', 'main', obj.target);\n            copyFile(plugin.dir, obj.src, project.projectDir, dest, !!(options && options.link));\n        },\n        uninstall: function (obj, plugin, project, options) {\n            const dest = path.join('app', 'src', 'main', obj.target);\n            removeFileF(path.resolve(project.projectDir, dest));\n        }\n    },\n    framework: {\n        install: function (obj, plugin, project, options) {\n            const src = obj.src;\n            if (!src) throw new CordovaError(generateAttributeError('src', 'framework', plugin.id));\n\n            events.emit('verbose', 'Installing Android library: ' + src);\n            const parentDir = obj.parent ? path.resolve(project.projectDir, obj.parent) : project.projectDir;\n            let subDir;\n\n            if (obj.custom) {\n                const subRelativeDir = project.getCustomSubprojectRelativeDir(plugin.id, src);\n                copyNewFile(plugin.dir, src, project.projectDir, subRelativeDir, !!(options && options.link));\n                subDir = path.resolve(project.projectDir, subRelativeDir);\n            } else {\n                obj.type = 'sys';\n                subDir = src;\n            }\n\n            if (obj.type === 'gradleReference') {\n                project.addGradleReference(parentDir, subDir);\n            } else if (obj.type === 'sys') {\n                project.addSystemLibrary(parentDir, subDir);","sourceCodeStart":57,"sourceCodeEnd":93,"githubUrl":"https://github.com/apache/cordova-android/blob/7c1e190064e349ffa4bbc6ac37b77cd773e4dbd3/lib/pluginHandlers.js#L57-L93","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["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\"/>","Check for misspelled attribute names (source= instead of src=) or the attribute accidentally placed on the parent <platform> element","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","For local plugin development, re-run `cordova plugin add <path>` after fixing the XML to re-parse plugin.xml"],"exampleFix":"<!-- before -->\n<platform name=\"android\">\n  <framework custom=\"true\" />\n</platform>\n\n<!-- after -->\n<platform name=\"android\">\n  <framework src=\"src/android/libs/mylib.aar\" custom=\"true\" />\n</platform>","handlingStrategy":"validation","validationCode":"// before installing a third-party plugin, lint its plugin.xml\nconst fs = require('fs');\nconst xml = fs.readFileSync('node_modules/<plugin>/plugin.xml', 'utf8');\nif (/<framework(?![^>]*\\bsrc=)[^>]*>/.test(xml.replace(/[\\r\\n]+/g, ' '))) {\n  throw new Error('plugin has a <framework> element without src — fix before `cordova plugin add`');\n}","typeGuard":null,"tryCatchPattern":"try {\n  await cordova.plugin('add', 'cordova-plugin-foo');\n} catch (e) {\n  if (e instanceof CordovaError && /Required attribute \"src\" not specified in <framework>/.test(e.message)) {\n    // point the user at the plugin's plugin.xml <framework> elements\n  }\n}","preventionTips":["Lint plugin.xml for required attributes in CI when authoring plugins","Test `cordova plugin add` of your own plugin in a fresh sandbox project before publishing"],"tags":["cordova","cordova-android","plugin-xml","framework","install"],"backgroundTag":"plugin-manifest-attribute-missing","analyzedSha":"7c1e190064e349ffa4bbc6ac37b77cd773e4dbd3","analyzedAt":"2026-08-22T04:57:58.868Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}