MuntashirAkon/AppManager · error · IOException

Stream closed

Error message

Stream closed

What it means

After argument validation, write() checks the closed flag and throws IOException("Stream closed") if the BZip2CompressorOutputStream has already been finished or closed. Writing to a closed compressor stream is invalid because the deflate state has been finalized.

Source

Thrown at app/src/main/java/org/apache/commons/compress/compressors/bzip2/BZip2CompressorOutputStream.java:618

        return this.blockSize100k;
    }

    @Override
    public void write(final byte[] buf, int offs, final int len)
            throws IOException {
        if (offs < 0) {
            throw new IndexOutOfBoundsException("offs(" + offs + ") < 0.");
        }
        if (len < 0) {
            throw new IndexOutOfBoundsException("len(" + len + ") < 0.");
        }
        if (offs + len > buf.length) {
            throw new IndexOutOfBoundsException("offs(" + offs + ") + len("
                    + len + ") > buf.length("
                    + buf.length + ").");
        }
        if (closed) {
            throw new IOException("Stream closed");
        }

        for (final int hi = offs + len; offs < hi;) {
            write0(buf[offs++]);
        }
    }

    /**
     * Keeps track of the last bytes written and implicitly performs
     * run-length encoding as the first step of the bzip2 algorithm.
     */
    private void write0(int b) throws IOException {
        if (this.currentChar != -1) {
            b &= 0xff;
            if (this.currentChar == b) {
                if (++this.runLength > 254) {
                    writeRun();
                    this.currentChar = -1;

View on GitHub (pinned to 0152f468fc)

Solutions

  1. Audit the code path and remove writes that occur after close()/finish().
  2. Guard writes with an isOpen/managed lifecycle check in your wrapper.
  3. Ensure exactly one close: rely on try-with-resources and drop manual close calls.

Example fix

// before
stream.close();
stream.write(data, 0, data.length);
// after
stream.write(data, 0, data.length);
stream.close();
Defensive patterns

Strategy: try-catch

Validate before calling

if (closed) {
    throw new IllegalStateException("compressor already closed");
}
out.write(buf, offs, len);

Try / catch

try {
    out.write(buf, offs, len);
} catch (IOException e) {
    if ("Stream closed".equals(e.getMessage())) {
        // lifecycle bug: write after close — re-open or drop the write
    } else {
        throw e;
    }
}

Prevention

When it happens

Trigger: Calling write() after close() or finish(); double-closing in try-with-resources followed by manual write; asynchronous writers using a stream another thread already closed.

Common situations: Calling close() twice (once explicitly, once via try-with-resources) with more writes in between; lifecycle bugs in code that flushes after shutdown; leaking a closed stream into a callback.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


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