skylot/jadx · error · IOException
{}, expected offset: 0x{}, actual: 0x{}
Error message
{}, expected offset: 0x{}, actual: 0x{} What it means
ParserStream.checkPos throws this when the current stream position does not equal a computed expected offset after parsing a chunk. This is a structural integrity check: each chunk declares its size, and after reading all fields the cursor must land exactly at chunkStart + chunkSize.
Source
Thrown at jadx-core/src/main/java/jadx/core/xmlgen/ParserStream.java:128
}
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()));
}
if (pos < expectedOffset) {
skip(expectedOffset - pos);
}
checkPos(expectedOffset, error);
}
@Override
public void mark(int len) {View on GitHub (pinned to e738a26571)
Solutions
- Re-extract resources.arsc from the original APK to rule out corruption
- Upgrade jadx to the latest release
- Report to jadx with the offset from the error message for format support
- As a workaround, disable resource decoding (jadx --no-res) to still decompile code
Example fix
// Disable resource decoding to bypass the parser entirely: // CLI: // jadx --no-res app.apk // API: jadxArgs.setSkipResources(true);
Defensive patterns
Strategy: try-catch
Validate before calling
// No pre-validation possible without parsing; check file integrity instead
if (Files.size(arsc) < 12) { throw new IllegalArgumentException("arsc too small"); } Try / catch
try {
resTableParser.decode(stream);
} catch (IOException e) {
if (e.getMessage().contains("expected offset")) {
LOG.warn("Resource structure mismatch, using --no-res", e);
jadxArgs.setSkipResources(true);
}
} Prevention
- Treat any positional validation failure as corrupt input
- Provide a code-only fallback path via --no-res
- Report reproducible cases to jadx maintainers
When it happens
Trigger: After fully reading a chunk's fields (e.g., type spec, library), checkPos compares getPos() to expectedEndPos. A mismatch means the declared chunk size and the actual bytes consumed diverge — indicating misaligned reads, wrong field sizes, or a malformed chunk. Also called directly by skipToPos as a final assertion.
Common situations: Malformed or hand-crafted resources.arsc where chunkSize is inconsistent with field layout. Resource obfuscation tools that shrink entries but leave chunkSize unchanged. Newer Android format extensions jadx does not yet parse, shifting the cursor. Partial corruption of a chunk.
Related errors
- {}, expected: 0x{}, actual: 0x{}, offset: 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/87808ebf211f8524.
Report an issue: GitHub.