apache/cordova-android · error · Error
AndroidManifest at ${path} has incorrect root node name (exp
Error message
AndroidManifest at ${path} has incorrect root node name (expected "manifest") What it means
The AndroidManifest wrapper class parses the given file with xmlHelpers.parseElementtreeSync in its constructor and requires the root element tag to be exactly 'manifest'. Thrown when the XML parses fine but is a different document type (root tag is 'widget', 'resources', 'html', etc.), i.e. you passed an XML file that is not an AndroidManifest.xml.
Source
Thrown at lib/AndroidManifest.js:31
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
*/
const fs = require('node:fs');
const xml = require('cordova-common').xmlHelpers;
const DEFAULT_ORIENTATION = 'default';
/** Wraps an AndroidManifest file */
class AndroidManifest {
constructor (path) {
this.path = path;
this.doc = xml.parseElementtreeSync(path);
if (this.doc.getroot().tag !== 'manifest') {
throw new Error('AndroidManifest at ' + path + ' has incorrect root node name (expected "manifest")');
}
}
getVersionName () {
return this.doc.getroot().attrib['android:versionName'];
}
setVersionName (versionName) {
this.doc.getroot().attrib['android:versionName'] = versionName;
return this;
}
getVersionCode () {
return this.doc.getroot().attrib['android:versionCode'];
}
setVersionCode (versionCode) {
this.doc.getroot().attrib['android:versionCode'] = versionCode;View on GitHub (pinned to 7c1e190064)
Solutions
- Pass the platform manifest path: platforms/android/app/src/main/AndroidManifest.xml.
- Inspect the file's first element (head -1) to confirm it starts with <manifest ...>.
- If the platform manifest is corrupted, regenerate it: `cordova platform rm android && cordova platform add android`.
Example fix
// before
const manifest = new AndroidManifest('config.xml');
// after
const manifest = new AndroidManifest(
path.join(projectRoot, 'platforms', 'android', 'app', 'src', 'main', 'AndroidManifest.xml')
); Defensive patterns
Strategy: validation
Validate before calling
const { xmlHelpers } = require('cordova-common');
function assertAndroidManifest (filePath) {
const doc = xmlHelpers.parseElementtreeSync(filePath);
if (doc.getroot().tag !== 'manifest') {
throw new Error(`${filePath} is not an AndroidManifest.xml (root: ${doc.getroot().tag})`);
}
return true;
} Type guard
const isManifestDoc = (doc) => Boolean(doc && typeof doc.getroot === 'function' && doc.getroot() && doc.getroot().tag === 'manifest');
Try / catch
try {
manifest = new AndroidManifest(candidatePath);
} catch (e) {
throw new Error(`Refusing ${candidatePath}: ${e.message} - expected platforms/android/app/src/main/AndroidManifest.xml`);
} Prevention
- Always derive the manifest path from the platform root (platforms/android/app/src/main/AndroidManifest.xml), never from user input or a glob.
- Name any auxiliary XML files something other than AndroidManifest.xml to avoid path mix-ups.
When it happens
Trigger: `new AndroidManifest(path)` with a path to config.xml, a stringified XML resource, or any XML whose root element is not <manifest>. Typically hit by tooling that updates versionName/versionCode (setVersionName/setVersionName on this class) with a wrong path.
Common situations: Passing config.xml instead of platforms/android/app/src/main/AndroidManifest.xml; a copy/template step that wraps the manifest in another element; globbing the first *.xml in a directory.
AI-assisted analysis of apache/cordova-android@7c1e190064 (2026-08-22).
Data as JSON: /api/errors/d28c620f1751d386.
Report an issue: GitHub.