iBotPeaches/Apktool · error · XmlPullParserException

Parser must be on TEXT or END_TAG to read text.

Error message

Parser must be on TEXT or END_TAG to read text.

What it means

Inside nextText(): after consuming the START_TAG, the next event must be TEXT or END_TAG (an empty element yields END_TAG and returns ""). Any other event type — START_TAG (nested element where text was expected) or END_DOCUMENT — throws this.

Source

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

    @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 {
        int eventType = next();
        if (eventType == TEXT && isWhitespace()) {
            eventType = next();
        }
        if (eventType != START_TAG && eventType != END_TAG) {
            throw new XmlPullParserException("Expected start or end tag.", this, null);
        }

View on GitHub (pinned to 79b63384d7)

Solutions

  1. Handle mixed content: iterate next() events inside the element and only treat TEXT events as text instead of calling nextText().
  2. If the element is genuinely text-only by spec, the input AXML is malformed — inspect it with `apktool d` or a hex dump.
  3. Guard with `if (parser.next() == XmlPullParser.TEXT)` patterns instead of assuming nextText() semantics.
  4. Verify the APK with aapt2 to rule out corruption.

Example fix

// before
String value = parser.nextText(); // throws on nested tags

// after (mixed-content-safe)
StringBuilder sb = new StringBuilder();
int depth = 1;
while (depth > 0) {
    int ev = parser.next();
    if (ev == XmlPullParser.TEXT) sb.append(parser.getText());
    else if (ev == XmlPullParser.START_TAG) depth++;
    else if (ev == XmlPullParser.END_TAG) depth--;
}
String value = sb.toString();
Defensive patterns

Strategy: validation

Validate before calling

int ev = parser.next();
if (ev == XmlPullParser.END_TAG) { /* empty element: text = "" */ }
else if (ev != XmlPullParser.TEXT) { /* mixed content: iterate events manually */ }

Try / catch

try {
    String text = parser.nextText();
} catch (XmlPullParserException e) {
    if (e.getMessage().contains("TEXT or END_TAG")) {
        // element has nested tags — fall back to manual event iteration
    }
}

Prevention

When it happens

Trigger: Calling nextText() on an element that contains a child element instead of text (e.g. `<string><b>hi</b></string>` style AXML), or a malformed binary XML whose events skip straight to END_DOCUMENT.

Common situations: Parsing app widgets/manifests where an element assumed to be text-only actually nests tags; AXML files whose event sequence was corrupted by packers; lenient hand-written XML fed through a compiler that kept nesting.

Related errors


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