{"record":{"id":"64266d83acbb5cd4","repo":"apache/cordova-android","slug":"required-attribute-target-not-specified-in-asse","errorCode":null,"errorMessage":"Required attribute \"target\" not specified in <asset> element from plugin: ${plugin.id}","messagePattern":"Required attribute \"target\" not specified in <asset> element from plugin: (.+?)","errorType":"validation","errorClass":"CordovaError","httpStatus":null,"severity":"error","filePath":"lib/pluginHandlers.js","lineNumber":135,"sourceCode":"                subDir = src;\n            }\n\n            if (obj.type === 'gradleReference') {\n                project.removeGradleReference(parentDir, subDir);\n            } else if (obj.type === 'sys') {\n                project.removeSystemLibrary(parentDir, subDir);\n            } else {\n                project.removeSubProject(parentDir, subDir);\n            }\n        }\n    },\n    asset: {\n        install: function (obj, plugin, project, options) {\n            if (!obj.src) {\n                throw new CordovaError(generateAttributeError('src', 'asset', plugin.id));\n            }\n            if (!obj.target) {\n                throw new CordovaError(generateAttributeError('target', 'asset', plugin.id));\n            }\n\n            copyFile(plugin.dir, obj.src, project.www, obj.target);\n            if (options && options.usePlatformWww) {\n                // CB-11022 copy file to both directories if usePlatformWww is specified\n                copyFile(plugin.dir, obj.src, project.platformWww, obj.target);\n            }\n        },\n        uninstall: function (obj, plugin, project, options) {\n            const target = obj.target || obj.src;\n\n            if (!target) {\n                throw new CordovaError(generateAttributeError('target', 'asset', plugin.id));\n            }\n\n            removeFileAndParents(project.www, target);\n            if (options && options.usePlatformWww) {\n                removeFileAndParents(project.platformWww, target);","sourceCodeStart":117,"sourceCodeEnd":153,"githubUrl":"https://github.com/apache/cordova-android/blob/7c1e190064e349ffa4bbc6ac37b77cd773e4dbd3/lib/pluginHandlers.js#L117-L153","documentation":"Thrown by the asset install handler when <asset> has src but no target attribute. target defines where inside the app's www directory the file lands; without it cordova-android cannot map the copy and rejects the plugin during install.","triggerScenarios":"`cordova plugin add <plugin>` where plugin.xml contains <asset src=\"www/foo.js\"/> with no target attribute. The handler checks src first, then throws generateAttributeError('target','asset',...) when !obj.target.","commonSituations":"Assuming src alone is enough (it is not on Android); copy-paste of <js-module> patterns where target does not exist; refactoring plugin.xml and losing the attribute.","solutions":["Add target to every <asset> element: <asset src=\"www/foo.js\" target=\"www/foo.js\"/>","Make sure target stays inside www (a leading slash or ../ in target will trip the path checks later)","Fix and republish the plugin if it ships in this state"],"exampleFix":"<!-- before -->\n<asset src=\"www/plugin-image.png\" />\n\n<!-- after -->\n<asset src=\"www/plugin-image.png\" target=\"www/img/plugin-image.png\" />","handlingStrategy":"validation","validationCode":"const fs = require('fs');\nconst xml = fs.readFileSync('node_modules/<plugin>/plugin.xml', 'utf8');\nif (/<asset(?![^>]*\\btarget=)[^>]*\\/>/.test(xml)) {\n  throw new Error('<asset> without target — fix plugin.xml before install');\n}","typeGuard":null,"tryCatchPattern":"try { await cordova.plugin('add', p); } catch (e) {\n  if (/Required attribute \"target\" not specified in <asset>/.test(e.message)) { /* add target to asset elements */ }\n}","preventionTips":["Pair src and target on every <asset>","Validate plugin.xml with a lint step before publishing"],"tags":["cordova","cordova-android","plugin-xml","asset","install"],"backgroundTag":"plugin-manifest-attribute-missing","analyzedSha":"7c1e190064e349ffa4bbc6ac37b77cd773e4dbd3","analyzedAt":"2026-08-22T04:57:58.868Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}