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

  1. Pass the platform manifest path: platforms/android/app/src/main/AndroidManifest.xml.
  2. Inspect the file's first element (head -1) to confirm it starts with <manifest ...>.
  3. 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

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.