{"record":{"id":"6d850d6bd7d2851f","repo":"apache/cordova-android","slug":"malformed-bom-platform-p","errorCode":null,"errorMessage":"Malformed BoM platform: ${p}","messagePattern":"Malformed BoM platform: (.+?)","errorType":"validation","errorClass":"CordovaError","httpStatus":null,"severity":"error","filePath":"lib/builders/ProjectBuilder.js","lineNumber":245,"sourceCode":"            }\n        };\n        subProjects.forEach(function (p) {\n            events.emit('log', 'Subproject Path: ' + p);\n            const libName = p.replace(/[/\\\\]/g, ':').replace(projectName + '-', '');\n            if (libName !== 'app') {\n                depsList += '    implementation(project(path: \":' + libName + '\"))';\n                insertExclude(p);\n            }\n        });\n        // For why we do this mapping: https://issues.apache.org/jira/browse/CB-8390\n        const SYSTEM_LIBRARY_MAPPINGS = [\n            [/^\\/?extras\\/android\\/support\\/(.*)$/, 'com.android.support:support-$1:+'],\n            [/^\\/?google\\/google_play_services\\/libproject\\/google-play-services_lib\\/?$/, 'com.google.android.gms:play-services:+']\n        ];\n\n        propertiesObj.bomPlatforms.forEach(function (p) {\n            if (!/:.*:/.exec(p)) {\n                throw new CordovaError('Malformed BoM platform: ' + p);\n            }\n\n            // Add bom platform\n            depsList += '    implementation platform(\"' + p + '\")\\n';\n        });\n\n        propertiesObj.systemLibs.forEach(function (p) {\n            let mavenRef;\n            // It's already in gradle form if it has two ':'s\n            if (/:.*:/.exec(p)) {\n                mavenRef = p;\n            } else if (/:.*/.exec(p)) {\n                // Support BoM imports\n                mavenRef = p;\n                events.emit('warn', 'Library expects a BoM package: ' + p);\n            } else {\n                for (let i = 0; i < SYSTEM_LIBRARY_MAPPINGS.length; ++i) {\n                    const pair = SYSTEM_LIBRARY_MAPPINGS[i];","sourceCodeStart":227,"sourceCodeEnd":263,"githubUrl":"https://github.com/apache/cordova-android/blob/7c1e190064e349ffa4bbc6ac37b77cd773e4dbd3/lib/builders/ProjectBuilder.js#L227-L263","documentation":"While regenerating app/build.gradle, ProjectBuilder collects every `cordova.system.library.N=platform('...')` line from project.properties into bomPlatforms and requires each captured value to match /:.*:/ - i.e. full gradle coordinates group:name:version - before emitting `implementation platform(\"...\")`. Thrown when the platform(...) value has fewer than two colons.","triggerScenarios":"A plugin (via its gradle/library declarations) or a hand-edited platforms/android/project.properties line such as `cordova.system.library.4=platform('firebase-bom')` or `platform('com.google.firebase:firebase-bom')` - anything without group:name:version. Happens during build prep (prepEnv writes app/build.gradle).","commonSituations":"Third-party plugin injecting a BoM without full Maven coordinates; copy-paste from docs that dropped the version segment; manual edits to project.properties after a platform regenerate.","solutions":["Fix the entry to full Maven coordinates: `cordova.system.library.4=platform('com.google.firebase:firebase-bom:32.7.0')`.","If you meant a plain dependency, drop the platform(...) wrapper and use bare coordinates `group:name:version` (those go through systemLibs instead).","Remove the offending numbered line entirely if the dependency is unneeded.","If a plugin injected the bad line, patch the plugin or pin a fixed version, then re-add the platform so project.properties is regenerated."],"exampleFix":"# before (platforms/android/project.properties)\ncordova.system.library.4=platform('com.google.firebase:firebase-bom')\n\n# after\ncordova.system.library.4=platform('com.google.firebase:firebase-bom:32.7.0')","handlingStrategy":"validation","validationCode":"const props = fs.readFileSync('platforms/android/project.properties', 'utf8');\nfor (const m of props.matchAll(/^\\s*cordova\\.system\\.library\\.\\d+=platform\\(['\"]?([^'\")]+)['\"]?\\)/gm)) {\n  if (!/:.+:.+/.test(m[1])) {\n    throw new Error(`BoM entry '${m[0]}' needs full group:name:version coordinates`);\n  }\n}","typeGuard":"const isGradleCoordinate = (s) => /^[^:]+:[^:]+:.+$/.test(s); // group:name:version","tryCatchPattern":"try {\n  await androidApi.build(opts);\n} catch (e) {\n  if (/Malformed BoM platform/.test(e.message)) {\n    // extract the printed value, point at the matching cordova.system.library.N line in project.properties\n  }\n  throw e;\n}","preventionTips":["Always write BoM entries as platform('group:name:version') with the version included.","When authoring plugins, run a scratch `cordova plugin add` + build in CI to catch bad <lib> declarations before release.","Re-generate the platform after fixing plugin declarations so project.properties is rewritten."],"tags":["gradle","bom","project-properties","dependency-notation","plugin"],"backgroundTag":"dependency-notation-invalid","analyzedSha":"7c1e190064e349ffa4bbc6ac37b77cd773e4dbd3","analyzedAt":"2026-08-22T04:57:58.868Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}