MuntashirAkon/AppManager · error · IOException

Unexpected end of stream

Error message

Unexpected end of stream

What it means

bsR() reads n bits via the underlying BitInputStream and throws IOException("Unexpected end of stream") when readBits returns a negative EOF marker. The stream ended while the decoder still expected structural data (block header, selectors, Huffman tables, or CRC).

Source

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

            try {
                inShadow.close();
            } finally {
                this.data = null;
                this.bin = null;
            }
        }
    }

    /**
     * read bits from the input stream
     * @param n the number of bits to read, must not exceed 32?
     * @return the requested bits combined into an int
     * @throws IOException
     */
    private static int bsR(final BitInputStream bin, final int n) throws IOException {
        final long thech = bin.readBits(n);
        if (thech < 0) {
            throw new IOException("Unexpected end of stream");
        }
        return (int) thech;
    }

    private static boolean bsGetBit(final BitInputStream bin) throws IOException {
        return bsR(bin, 1) != 0;
    }

    private static char bsGetUByte(final BitInputStream bin) throws IOException {
        return (char) bsR(bin, 8);
    }

    private static int bsGetInt(final BitInputStream bin) throws IOException {
        return bsR(bin, 32);
    }

    private static void checkBounds(final int checkVal, final int limitExclusive, final String name)
            throws IOException {

View on GitHub (pinned to 0152f468fc)

Solutions

  1. Ensure the compressed input is complete: wait for the producer to finish and close, or re-download fully.
  2. Verify the file with `bzip2 -t` (reports 'unexpected end of file' for truncated archives).
  3. Always close() the compressor OutputStream on the producer side so the end-of-stream trailer is written.
  4. Catch IOException and handle truncation explicitly if partial data is acceptable, but do not retry reading the same truncated source.

Example fix

// before
// producer side: forgot to close, trailer missing
compressorOutputStream.finish(); // incomplete: no close()
// after
try (BZip2CompressorOutputStream out = new BZip2CompressorOutputStream(fileOut)) {
    out.write(data);
} // close() writes the stream trailer
Defensive patterns

Strategy: try-catch

Validate before calling

// check completeness before decompress
long expected = manifest.get(name);
if (file.length() < expected) throw new IOException("truncated download: " + file);

Try / catch

try {
    readAll(in);
} catch (IOException e) {
    if ("Unexpected end of stream".equals(e.getMessage())) {
        // source truncated: re-download or wait for producer to finish
        throw new TruncatedInputException(e);
    }
    throw e;
}

Prevention

When it happens

Trigger: A truncated .bz2 file (download cut off, write not flushed/closed); the underlying InputStream hit EOF mid-block or before the stream trailer; feeding a stream that is still being written concurrently.

Common situations: Partially downloaded files; producer not closing the OutputStream so the compressor never flushed the trailer; reading over an unstable socket connection; reading a file currently being written by another process.

Related errors


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