{"record":{"id":"6de6b54e2507d52e","repo":"skylot/jadx","slug":"expected-offset-not-reachable-0x-actual-0","errorCode":null,"errorMessage":"{}, expected offset not reachable: 0x{}, actual: 0x{}","messagePattern":"(.+?), expected offset not reachable: 0x(.+?), actual: 0x(.+?)","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"jadx-core/src/main/java/jadx/core/xmlgen/ParserStream.java","lineNumber":136,"sourceCode":"\n\tprivate void throwException(String error, int expected, int actual) throws IOException {\n\t\tthrow new IOException(error\n\t\t\t\t+ \", expected: 0x\" + Integer.toHexString(expected)\n\t\t\t\t+ \", actual: 0x\" + Integer.toHexString(actual)\n\t\t\t\t+ \", offset: 0x\" + Long.toHexString(getPos()));\n\t}\n\n\tpublic void checkPos(long expectedOffset, String error) throws IOException {\n\t\tif (getPos() != expectedOffset) {\n\t\t\tthrow new IOException(error + \", expected offset: 0x\" + Long.toHexString(expectedOffset)\n\t\t\t\t\t+ \", actual: 0x\" + Long.toHexString(getPos()));\n\t\t}\n\t}\n\n\tpublic void skipToPos(long expectedOffset, String error) throws IOException {\n\t\tlong pos = getPos();\n\t\tif (pos > expectedOffset) {\n\t\t\tthrow new IOException(error + \", expected offset not reachable: 0x\" + Long.toHexString(expectedOffset)\n\t\t\t\t\t+ \", actual: 0x\" + Long.toHexString(getPos()));\n\t\t}\n\t\tif (pos < expectedOffset) {\n\t\t\tskip(expectedOffset - pos);\n\t\t}\n\t\tcheckPos(expectedOffset, error);\n\t}\n\n\t@Override\n\tpublic void mark(int len) {\n\t\tif (!input.markSupported()) {\n\t\t\tthrow new RuntimeException(\"Mark not supported for input stream \" + input.getClass());\n\t\t}\n\t\tinput.mark(len);\n\t\tmarkPos = readPos;\n\t}\n\n\t@Override","sourceCodeStart":118,"sourceCodeEnd":154,"githubUrl":"https://github.com/skylot/jadx/blob/e738a26571d02919f01df40de93bc9a44dee4e18/jadx-core/src/main/java/jadx/core/xmlgen/ParserStream.java#L118-L154","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// Skip resources if parsing fails:\ntry {\n    jadxArgs.setSkipResources(false);\n    decompiler.load();\n} catch (Exception e) {\n    jadxArgs.setSkipResources(true);\n    decompiler.load();\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n    resTableParser.decode(stream);\n} catch (IOException e) {\n    if (e.getMessage().contains(\"not reachable\")) {\n        LOG.warn(\"Backward offset in resources, skipping resource decode\", e);\n        jadxArgs.setSkipResources(true);\n    }\n}","preventionTips":["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"],"tags":["android","binary-parsing","validation","resource-table","corrupt-input"],"backgroundTag":null,"analyzedSha":"e738a26571d02919f01df40de93bc9a44dee4e18","analyzedAt":"2026-08-14T00:10:24.238Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}