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
- Verify the file is genuinely an Android binary resource file (resources.arsc or *.axml)
- Re-extract the resource from the APK to rule out corruption
- Upgrade jadx to a version that supports the resource format variant you encountered
- 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
- Validate the resource file type before parsing
- Keep jadx updated for new format support
- Use aapt/apktool as a cross-check for valid resources
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
- {}, expected offset: 0x{}, actual: 0x{}
- {}, expected offset not reachable: 0x{}, actual: 0x{}
- Error reading type spec chunk at offset 0x%x
- reading after chunk end
- Error reading library chunk at offset 0x%x
AI-assisted analysis of skylot/jadx@e738a26571 (2026-08-14).
Data as JSON: /api/errors/3428e99954b546f0.
Report an issue: GitHub.