iBotPeaches/Apktool · error · IOException

Illegal backwards jump from %s to %s

Error message

Illegal backwards jump from %s to %s

What it means

BinaryDataInputStream.jumpTo(pos) only supports seeking forward over the underlying stream by skipping; requesting a position before the current one throws this IOException. It is a parser-level invariant violation, not a stream failure: the caller computed an offset that lies behind the read cursor.

Source

Thrown at brut.j.util/src/main/java/brut/util/BinaryDataInputStream.java:86

    public long limit() {
        return mLimit;
    }

    public long position() {
        return mPosition;
    }

    public long remaining() {
        return mLimit - mPosition;
    }

    public long jumpTo(long pos) throws IOException {
        long expected = pos - mPosition;
        if (expected == 0) {
            return 0;
        }
        if (expected < 0) {
            throw new IOException(String.format("Illegal backwards jump from %s to %s", mPosition, pos));
        }
        long skipped = skip(expected);
        if (skipped != expected) {
            throw new IOException(String.format("Jump failed: skipped %s bytes (expected: %s)", skipped, expected));
        }
        return skipped;
    }

    public void skipByte() throws IOException {
        //noinspection ResultOfMethodCallIgnored
        readByte();
    }

    public void skipShort() throws IOException {
        //noinspection ResultOfMethodCallIgnored
        readShort();
    }

View on GitHub (pinned to 79b63384d7)

Solutions

  1. Verify the file is an intact, original APK (`unzip -t`, re-download) — malformed tables are the usual cause
  2. Update apktool; offset-handling fixes for new resources.arsc encodings land regularly
  3. If you control the file, rebuild the resource table with aapt2 to normalize offsets
  4. Reproduce with a minimal file and report to apktool if a genuine parser bug is suspected

Example fix

// before
long pos = stringPoolOffset; // may be < current position on odd files
in.jumpTo(pos);

// after
if (pos < in.position()) {
    throw new IOException("Chunk offset " + pos + " precedes current position " + in.position()
        + " — resources.arsc is malformed");
}
in.jumpTo(pos);
Defensive patterns

Strategy: validation

Validate before calling

// Validate offsets before jumping during custom parsing
long target = chunkOffset;
if (target < in.position()) {
    throw new IOException("Malformed table: offset " + target + " < current " + in.position());
}
in.jumpTo(target);

Try / catch

try {
    in.jumpTo(pos);
} catch (IOException e) {
    if (e.getMessage() != null && e.getMessage().startsWith("Illegal backwards jump")) {
        // file's chunk layout is inconsistent — abort parse with file context, do not retry
        throw new ParseAbortException("Malformed resources.arsc", e);
    }
    throw e;
}

Prevention

When it happens

Trigger: Parsing resources.arsc/AXML where a chunk length or string-pool offset points backwards past already-consumed bytes (malformed or hostile file), or a parser bug that mis-tracks mPosition after mark/reset.

Common situations: Decoding a hand-crafted or corrupted resources.arsc; files produced by packers/protectors that rewrite resource tables with unusual layouts; occasionally an apktool version's parser misreading a newer table format.

Related errors


AI-assisted analysis of iBotPeaches/Apktool@79b63384d7 (2026-08-14). Data as JSON: /api/errors/e05447587da24e7c. Report an issue: GitHub.