iBotPeaches/Apktool · error · XmlPullParserException

Parser must be on START_TAG to read next text.

Error message

Parser must be on START_TAG to read next text.

What it means

Standard XmlPullParser contract enforced by BinaryXmlResourceParser.nextText(): the parser must currently sit on a START_TAG event. Calling nextText() in any other state (TEXT, END_TAG, END_DOCUMENT, before next()) violates the contract and throws immediately.

Source

Thrown at brut.apktool/apktool-lib/src/main/java/brut/androlib/res/decoder/BinaryXmlResourceParser.java:549

    }

    @Override
    public int nextToken() throws XmlPullParserException, IOException {
        return next();
    }

    @Override
    public void require(int type, String namespace, String name) throws XmlPullParserException {
        if (type != mEventType || (namespace != null && !namespace.equals(getNamespace()))
                || (name != null && !name.equals(getName()))) {
            throw new XmlPullParserException(TYPES[type] + " is expected.", this, null);
        }
    }

    @Override
    public String nextText() throws XmlPullParserException, IOException {
        if (mEventType != START_TAG) {
            throw new XmlPullParserException("Parser must be on START_TAG to read next text.", this, null);
        }
        int eventType = next();
        if (eventType == END_TAG) {
            return "";
        }
        if (eventType != TEXT) {
            throw new XmlPullParserException("Parser must be on TEXT or END_TAG to read text.", this, null);
        }
        String result = getText();
        eventType = next();
        if (eventType != END_TAG) {
            throw new XmlPullParserException("Event TEXT must be immediately followed by END_TAG.", this, null);
        }
        return result;
    }

    @Override
    public int nextTag() throws XmlPullParserException, IOException {

View on GitHub (pinned to 79b63384d7)

Solutions

  1. Always reach the tag with nextTag() (or check getEventType() == START_TAG) before nextText().
  2. Use the canonical loop: `while ((t = parser.next()) != END_DOCUMENT) { if (t == START_TAG && "name".equals(parser.getName())) { String text = parser.nextText(); } }`.
  3. Add an assertion/guard on parser.getEventType() before nextText() during development.
  4. If this fires on apktool's own parsing, the AXML likely has malformed structure — verify with apktool d on a known-good APK.

Example fix

// before
while (parser.next() != XmlPullParser.END_DOCUMENT) {
    parser.nextText(); // may not be on START_TAG
}

// after
int t;
while ((t = parser.next()) != XmlPullParser.END_DOCUMENT) {
    if (t == XmlPullParser.START_TAG && "expected".equals(parser.getName())) {
        String text = parser.nextText();
    }
}
Defensive patterns

Strategy: validation

Validate before calling

if (parser.getEventType() != XmlPullParser.START_TAG) {
    throw new IllegalStateException("nextText() requires START_TAG, at " + parser.getPositionDescription());
}

Try / catch

if (parser.getEventType() == XmlPullParser.START_TAG) {
    text = parser.nextText();
} else {
    // skip or handle non-tag event
}

Prevention

When it happens

Trigger: Client code calls nextText() without a preceding nextTag()/next() that lands on START_TAG — e.g. looping `while (parser.next() != END_DOCUMENT) { parser.nextText(); }`, or calling nextText() after the loop already consumed the tag.

Common situations: Hand-written XmlPullParser traversal code adapted from a DOM/SAX mindset; refactors that inserted an extra next() call; parsers reused across files without reset so event state is stale.

Related errors


AI-assisted analysis of iBotPeaches/Apktool@79b63384d7 (2026-08-14). Data as JSON: /api/errors/843b4e58d32c1964. Report an issue: GitHub.