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;
	}

	@Override

View on GitHub (pinned to e738a26571)

Solutions

  1. Re-extract the resource file from a clean APK copy
  2. Upgrade jadx to the latest version
  3. Report the file to jadx maintainers with the offsets from the error
  4. 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

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


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