MuntashirAkon/AppManager · error · IOException

Closed

Error message

Closed

What it means

write(int) checks whether the output stream has already been closed; writing after close() is an invalid state and throws IOException("Closed"). A closed BZip2CompressorOutputStream has finalized the bzip2 stream and cannot accept more data.

Source

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

        if (blockSize < 1) {
            throw new IllegalArgumentException("blockSize(" + blockSize + ") < 1");
        }
        if (blockSize > 9) {
            throw new IllegalArgumentException("blockSize(" + blockSize + ") > 9");
        }

        this.blockSize100k = blockSize;
        this.out = out;

        /* 20 is just a paranoia constant */
        this.allowableBlockSize = (this.blockSize100k * BZip2Constants.BASEBLOCKSIZE) - 20;
        init();
    }

    @Override
    public void write(final int b) throws IOException {
        if (closed) {
            throw new IOException("Closed");
        }
        write0(b);
    }

    /**
     * Writes the current byte to the buffer, run-length encoding it
     * if it has been repeated at least four times (the first step
     * RLEs sequences of four identical bytes).
     *
     * <p>Flushes the current block before writing data if it is
     * full.</p>
     *
     * <p>"write to the buffer" means adding to data.buffer starting
     * two steps "after" this.last - initially starting at index 1
     * (not 0) - and updating this.last to point to the last index
     * written minus 1.</p>
     */
    private void writeRun() throws IOException {

View on GitHub (pinned to 0152f468fc)

Solutions

  1. Stop writing after close(); restructure so close() happens only when all data is written.
  2. Open a new BZip2CompressorOutputStream for additional data instead of reusing a closed one.
  3. Ensure only one owner closes the stream (try-with-resources around the entire write path).
  4. Guard with an isClosed()/closed flag check before writing if lifecycle is complex.

Example fix

// before
try (BZip2CompressorOutputStream b = new BZip2CompressorOutputStream(fos)) {
    b.write(header);
}
b.write(footer); // stream already closed -> IOException: Closed
// after
try (BZip2CompressorOutputStream b = new BZip2CompressorOutputStream(fos)) {
    b.write(header);
    b.write(footer);
}
Defensive patterns

Strategy: try-catch

Try / catch

if (!closed) {
    try { stream.write(b); } catch (IOException e) {
        if ("Closed".equals(e.getMessage())) throw new IllegalStateException("write after close", e);
        throw e;
    }
}

Prevention

When it happens

Trigger: Calling write(byte), write(byte[]), or close()-dependent wrappers after close() was invoked — e.g. writing via the same reference twice, try-with-resources followed by manual writes, or a copied reference to a stream closed elsewhere.

Common situations: Double-close in layered stream code, buffering writes after try-with-resources scope ends, a utility method closing the caller's stream then the caller writing more, caching the stream in a field after a completed unit of work.

Related errors


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