iBotPeaches/Apktool · error · XmlPullParserException
Expected start or end tag.
Error message
Expected start or end tag.
What it means
nextTag() requires the next (non-whitespace-text) event to be START_TAG or END_TAG; it is the convenience method for tag-only iteration. Encountering TEXT with non-whitespace content, or END_DOCUMENT, throws this error.
Source
Thrown at brut.apktool/apktool-lib/src/main/java/brut/androlib/res/decoder/BinaryXmlResourceParser.java:573
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);
}
return eventType;
}
// Utility methods
private Attribute getAttribute(int index) {
if (mEventType != START_TAG) {
throw new IndexOutOfBoundsException("Parser must be on START_TAG to get attributes.");
}
if (mAttributes == null || index < 0 || index >= mAttributes.length) {
throw new IndexOutOfBoundsException(
String.format("Attribute index out of range: index=%s, length=%s",
index, mAttributes != null ? mAttributes.length : 0));
}
return mAttributes[index];
}
View on GitHub (pinned to 79b63384d7)
Solutions
- Bound loops on the specific END_TAG of the parent element, not just END_DOCUMENT, so nextTag() is never called at EOF.
- For mixed content, use next() and filter events instead of nextTag().
- Skip whitespace-only TEXT is handled internally — real text means restructure the traversal.
- During development, log getEventType()/getName() before each nextTag() to find the offending position.
Example fix
// before
while (parser.getEventType() != XmlPullParser.END_DOCUMENT) {
parser.nextTag(); // throws at EOF / on text
}
// after
parser.require(XmlPullParser.START_TAG, null, "root");
while (parser.nextTag() == XmlPullParser.START_TAG) {
// handle element
// consume to its END_TAG:
while (parser.next() != XmlPullParser.END_TAG) { /* skip */ }
} Defensive patterns
Strategy: validation
Validate before calling
int ev = parser.next();
if (ev == XmlPullParser.TEXT && parser.isWhitespace()) ev = parser.next();
if (ev != XmlPullParser.START_TAG && ev != XmlPullParser.END_TAG) {
// not tag-only content — use next() traversal instead of nextTag()
} Try / catch
try {
int ev = parser.nextTag();
} catch (XmlPullParserException e) {
if (e.getMessage().equals("Expected start or end tag.")) {
// encountered real text or EOF — restructure the loop bounds
}
} Prevention
- Bound nextTag() loops on the parent END_TAG, not just END_DOCUMENT.
- Use next() + event filtering for mixed-content XML.
When it happens
Trigger: Calling nextTag() on XML that contains character data between tags (mixed content), or reaching the end of the document — e.g. unconditionally calling nextTag() in a loop that runs past the final END_TAG.
Common situations: Tag-walking loops like `while (parser.getEventType() != END_DOCUMENT) parser.nextTag();` that hit trailing text or EOF; parsing AXML with text nodes where the developer assumed tags only; malformed event streams.
Related errors
- Parser must be on START_TAG to read next text.
- Could not initialize parser.
- Parser must be on TEXT or END_TAG to read text.
- Event TEXT must be immediately followed by END_TAG.
- Attribute index out of range: index=%s, length=%s
AI-assisted analysis of iBotPeaches/Apktool@79b63384d7 (2026-08-14).
Data as JSON: /api/errors/de26a3c0041367e4.
Report an issue: GitHub.