skylot/jadx · error · IOException

Decode error: ${message}, position: 0x${position}

Error message

Decode error: ${message}, position: 0x${position}

What it means

Thrown by CommonBinaryParser.die(String) as an IOException (not JadxRuntimeException) when the binary XML parser encounters a structural error in an Android binary XML resource (e.g., AndroidManifest.xml, layout XML). The message includes a human-readable reason and the current byte position (hex) in the stream. This is the parser's fatal-error signal for malformed or truncated binary XML chunks — used when expected magic numbers, chunk sizes, or string-pool boundaries don't match.

Source

Thrown at jadx-core/src/main/java/jadx/core/xmlgen/CommonBinaryParser.java:50

		int styleCount = is.readInt32();
		int flags = is.readInt32();
		long stringsStart = is.readInt32();
		long stylesStart = is.readInt32();

		// Correct the offset of actual strings, as the header is already read.
		stringsStart = stringsStart - (is.getPos() - start);
		byte[] buffer = is.readInt8Array((int) (chunkEnd - is.getPos()));
		is.checkPos(chunkEnd, "Expected strings pool end");

		return new BinaryXMLStrings(
				stringCount,
				stringsStart,
				buffer,
				(flags & UTF8_FLAG) != 0);
	}

	protected void die(String message) throws IOException {
		throw new IOException("Decode error: " + message
				+ ", position: 0x" + Long.toHexString(is.getPos()));
	}
}

View on GitHub (pinned to e738a26571)

Solutions

  1. Catch IOException around the parse() call and log the position for diagnosis.
  2. Re-download or re-obtain the APK from a trusted source to rule out truncation.
  3. Use apktool or aapt to validate the binary XML independently.
  4. If obfuscation is suspected, try --no-debug-info or relaxed parsing options in jadx.

Example fix

// before
ICodeInfo info = parser.parse(inputStream);

// after — catch the IOException and degrade gracefully
try {
    ICodeInfo info = parser.parse(inputStream);
} catch (IOException e) {
    LOG.warn("Binary XML parse failed: {}", e.getMessage());
    // fall back to raw output or skip this resource
}
Defensive patterns

Strategy: try-catch

Validate before calling

// No programmatic pre-validation possible for binary XML internals.
// Best effort: check the file starts with a binary XML magic number.
public static boolean looksLikeBinaryXml(byte[] header) {
    // Android binary XML starts with 0x00080003 (little-endian: 03 00 08 00)
    return header != null && header.length >= 4
        && header[0] == 0x03 && header[1] == 0x00
        && header[2] == 0x08 && header[3] == 0x00;
}

Try / catch

try {
    ICodeInfo info = parser.parse(inputStream);
} catch (IOException e) {
    LOG.warn("Binary XML decode error at {}: {}", e.getMessage());
    // degrade gracefully: skip resource or output raw bytes
}

Prevention

When it happens

Trigger: Parsing a binary Android XML resource that is corrupted, truncated, or not actually binary XML (wrong chunk type). A malformed string pool where chunkEnd doesn't align (is.checkPos fails). Invalid header sizes or magic values in the RES_STRING_POOL_TYPE check. Deliberately malformed XML from an obfuscator or packer.

Common situations: Decompiling a packed/obfuscated APK with intentionally corrupted resources.arsc or AndroidManifest.xml. A truncated APK download. A resource file that was processed by an aggressive resource shrinker/proguard. An anti-decompilation tool that corrupts binary XML headers.

Related errors


AI-assisted analysis of skylot/jadx@e738a26571 (2026-08-14). Data as JSON: /api/errors/c66c2282e6be8dd4. Report an issue: GitHub.