skylot/jadx · error · IOException
{}, expected offset not reachable: 0x{}, actual: 0x{}
Error message
{}, expected offset not reachable: 0x{}, actual: 0x{} What it means
ParserStream.skipToPos throws this when the current stream position is already past the target offset, making it impossible to skip forward to it. This occurs when a declared offset points backward relative to where the parser currently sits.
Source
Thrown at jadx-core/src/main/java/jadx/core/xmlgen/ParserStream.java:136
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) {
if (!input.markSupported()) {
throw new RuntimeException("Mark not supported for input stream " + input.getClass());
}
input.mark(len);
markPos = readPos;
}
@OverrideView on GitHub (pinned to e738a26571)
Solutions
- Re-extract the resource file from a clean APK copy
- Upgrade jadx to the latest version
- Report the file to jadx maintainers with the offsets from the error
- Use jadx --no-res to skip resource decoding if only code is needed
Example fix
// Skip resources if parsing fails:
try {
jadxArgs.setSkipResources(false);
decompiler.load();
} catch (Exception e) {
jadxArgs.setSkipResources(true);
decompiler.load();
} Defensive patterns
Strategy: try-catch
Try / catch
try {
resTableParser.decode(stream);
} catch (IOException e) {
if (e.getMessage().contains("not reachable")) {
LOG.warn("Backward offset in resources, skipping resource decode", e);
jadxArgs.setSkipResources(true);
}
} Prevention
- Ensure the stream starts at offset 0 (not pre-read)
- Use clean APK extractions
- Catch and degrade to code-only mode on structural offset errors
When it happens
Trigger: skipToPos(expectedOffset, error) checks getPos() > expectedOffset before skipping. If the parser has already read past the target (e.g., a string pool offset or chunk end that is smaller than the current position), it cannot rewind and throws. This commonly happens when offsets are relative-vs-absolute misinterpreted or when fields overlap.
Common situations: Corrupt resources.arsc with invalid offsets. Obfuscation that zeroes or randomizes offset fields. Newer format where offset semantics changed. Reading a file that was already partially consumed before being passed to the parser.
Related errors
- {}, expected: 0x{}, actual: 0x{}, offset: 0x{}
- {}, expected offset: 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/6de6b54e2507d52e.
Report an issue: GitHub.