MuntashirAkon/AppManager · error · IOException

Stream corrupted

Error message

Stream corrupted

What it means

After building the inverse-BWT 'tt' table, the decoder validates origPtr (the starting pointer stored in the block header) against the table bounds. If origPtr is negative or beyond tt.length, the block header is inconsistent with the decoded data — the stream is corrupt and cannot be inverted.

Source

Thrown at app/src/main/java/org/apache/commons/compress/compressors/bzip2/BZip2CompressorInputStream.java:755

        final int ttLen = this.last + 1;
        final int[] tt = this.data.initTT(ttLen);
        final byte[] ll8 = this.data.ll8;
        cftab[0] = 0;
        System.arraycopy(this.data.unzftab, 0, cftab, 1, 256);

        for (int i = 1, c = cftab[0]; i <= 256; i++) {
            c += cftab[i];
            cftab[i] = c;
        }

        for (int i = 0, lastShadow = this.last; i <= lastShadow; i++) {
            final int tmp = cftab[ll8[i] & 0xff]++;
            checkBounds(tmp, ttLen, "tt index");
            tt[tmp] = i;
        }

        if ((this.origPtr < 0) || (this.origPtr >= tt.length)) {
            throw new IOException("Stream corrupted");
        }

        this.su_tPos = tt[this.origPtr];
        this.su_count = 0;
        this.su_i2 = 0;
        this.su_ch2 = 256; /* not a char and not EOF */

        if (this.blockRandomised) {
            this.su_rNToGo = 0;
            this.su_rTPos = 0;
            return setupRandPartA();
        }
        return setupNoRandPartA();
    }

    private int setupRandPartA() throws IOException {
        if (this.su_i2 <= this.last) {
            this.su_chPrev = this.su_ch2;

View on GitHub (pinned to 0152f468fc)

Solutions

  1. Validate the source with `bzip2 -t` and replace the corrupt file.
  2. Confirm you decompress the complete stream from byte 0 (no offsets/resume).
  3. Catch IOException and convert to a domain-specific 'corrupt archive' error for callers.
  4. Keep commons-compress updated — these checks are additions from hardening fixes; older versions may crash instead.

Example fix

// before
new BZip2CompressorInputStream(raw); // may throw 'Stream corrupted' mid-read
// after
try (BZip2CompressorInputStream bz = new BZip2CompressorInputStream(raw)) {
    // read
} catch (IOException e) {
    throw new CorruptArchiveException("invalid bzip2 stream: " + e.getMessage(), e);
}
Defensive patterns

Strategy: try-catch

Try / catch

try (BZip2CompressorInputStream bz = new BZip2CompressorInputStream(raw)) {
    // read
} catch (IOException e) {
    if ("Stream corrupted".equals(e.getMessage()))
        throw new CorruptArchiveException("bad origPtr / corrupt block", e);
    throw e;
}

Prevention

When it happens

Trigger: BZip2CompressorInputStream.read() during final BWT inversion in setupBlock/getAndMoveToFrontDecode: origPtr from the block header falls outside tt.length.

Common situations: Corrupted block headers from truncated/flipped-bit files, crafted malicious archives, feeding non-bzip2 bytes to the decompressor.

Related errors


AI-assisted analysis of MuntashirAkon/AppManager@0152f468fc (2026-09-12). Data as JSON: /api/errors/4aca4a80ad51a6bd. Report an issue: GitHub.