skylot/jadx · error · IOException

{}, expected: 0x{}, actual: 0x{}, offset: 0x{}

Error message

{}, expected: 0x{}, actual: 0x{}, offset: 0x{}

What it means

ParserStream.throwException is invoked by checkInt8/checkInt16 when a read magic/value does not match an expected constant. The message includes the expected and actual hex values plus the current offset, giving precise diagnostics for structural validation failures in Android binary resource headers.

Source

Thrown at jadx-core/src/main/java/jadx/core/xmlgen/ParserStream.java:120

		return pos;
	}

	public void checkInt8(int expected, String error) throws IOException {
		int v = readInt8();
		if (v != expected) {
			throwException(error, expected, v);
		}
	}

	public void checkInt16(int expected, String error) throws IOException {
		int v = readInt16();
		if (v != expected) {
			throwException(error, expected, v);
		}
	}

	private void throwException(String error, int expected, int actual) throws IOException {
		throw new IOException(error
				+ ", expected: 0x" + Integer.toHexString(expected)
				+ ", actual: 0x" + Integer.toHexString(actual)
				+ ", offset: 0x" + Long.toHexString(getPos()));
	}

	public void checkPos(long expectedOffset, String error) throws IOException {
		if (getPos() != expectedOffset) {
			throw new IOException(error + ", expected offset: 0x" + Long.toHexString(expectedOffset)
					+ ", actual: 0x" + Long.toHexString(getPos()));
		}
	}

	public void skipToPos(long expectedOffset, String error) throws IOException {
		long pos = getPos();
		if (pos > expectedOffset) {
			throw new IOException(error + ", expected offset not reachable: 0x" + Long.toHexString(expectedOffset)
					+ ", actual: 0x" + Long.toHexString(getPos()));
		}

View on GitHub (pinned to e738a26571)

Solutions

  1. Verify the file is genuinely an Android binary resource file (resources.arsc or *.axml)
  2. Re-extract the resource from the APK to rule out corruption
  3. Upgrade jadx to a version that supports the resource format variant you encountered
  4. File a jadx bug report including the offset, expected, and actual values from the error

Example fix

// Validate file type before decoding:
byte[] magic = Files.readAllBytes(path);
if (magic.length < 4 || magic[0] != 0x02 || magic[1] != 0x00) {
    throw new IllegalArgumentException("Not a valid Android binary resource");
}
Defensive patterns

Strategy: validation

Validate before calling

// Sniff the first bytes to confirm Android binary resource format:
byte[] head = new byte[4];
try (InputStream is = Files.newInputStream(path)) {
    is.read(head);
}
boolean isBinaryRes = (head[0] & 0xFF) == 0x02 && (head[1] & 0xFF) == 0x00;
if (!isBinaryRes) { /* not a valid AXML/arsc */ }

Try / catch

try {
    parser.decode(stream);
} catch (IOException e) {
    if (e.getMessage().contains("expected: 0x")) {
        LOG.warn("Format mismatch, skipping resources", e);
    }
}

Prevention

When it happens

Trigger: checkInt16(expected, error) or checkInt8(expected, error) reads a value and compares it to a hard-coded constant (e.g., header size 0x0010, magic bytes). A mismatch means the binary structure does not conform to the expected Android resource format at that offset. Common callers: parseTypeSpecChunk (header size 0x0010), parseLibraryTypeChunk (header size 12), parseValue (size 8, res0 0).

Common situations: Parsing a binary XML or resource table produced by a non-standard or newer Android build tool that changed header layout. File corruption flipping bytes in the header. Passing a raw class file or PNG as if it were resources.arsc. Obfuscated apps with intentionally mangled resource headers.

Related errors


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