apache/hadoop · error · IOException

closed

Error message

closed

What it means

CBZip2OutputStream.write(int) checks the internal output stream reference; after close() the codec nulls this.out, so any subsequent single-byte write throws IOException("closed"). The object intentionally refuses work once it has been closed instead of silently dropping bytes. It is a lifecycle error in the caller's code, not data corruption.

Source

Thrown at hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/io/compress/bzip2/CBZip2OutputStream.java:650

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

    this.blockSize100k = blockSize;
    this.out = out;
    init();
  }

  @Override
  public void write(final int b) throws IOException {
    if (this.out != null) {
      write0(b);
    } else {
      throw new IOException("closed");
    }
  }

  private void writeRun() throws IOException {
    final int lastShadow = this.last;

    if (lastShadow < this.allowableBlockSize) {
      final int currentCharShadow = this.currentChar;
      final Data dataShadow = this.data;
      dataShadow.inUse[currentCharShadow] = true;
      final byte ch = (byte) currentCharShadow;

      int runLengthShadow = this.runLength;
      this.crc.updateCRC(currentCharShadow, runLengthShadow);

      switch (runLengthShadow) {
      case 1:
        dataShadow.block[lastShadow + 2] = ch;

View on GitHub (pinned to 2add963021)

Solutions

  1. Fix the lifecycle: ensure close() happens exactly once, after all writes — use try-with-resources around the outermost wrapper owning the stream.
  2. Track ownership explicitly (one component owns close; the rest only write) or guard with an AtomicBoolean closed flag.
  3. Null out your own reference after close so later writes fail on a clear NullPointerException at your site rather than inside the codec.
  4. In multithreaded writers, synchronize write/close on a single monitor so close cannot interleave with pending writes.

Example fix

// before
cbz.close();
cbz.write(b); // IOException: closed

// after
try (CBZip2OutputStream cbz = new CBZip2OutputStream(out)) {
  cbz.write(b);
} // close happens once, after all writes
Defensive patterns

Strategy: try-catch

Validate before calling

// Track ownership outside the codec
private boolean closed = false;

void safeWrite(int b) throws IOException {
  if (closed) throw new IllegalStateException("writer already closed");
  cbz.write(b);
}

Try / catch

try {
  cbz.write(b);
} catch (IOException e) {
  if ("closed".equals(e.getMessage())) {
    throw new IllegalStateException("bug: write after close", e);
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling write(int) on a CBZip2OutputStream after close() has run: double-processing the same writer, a finally block that closes early, nested wrappers where an inner close() nulls the stream and an outer wrapper keeps writing, or cleanup code racing with a producer thread.

Common situations: Utility wrappers (DataOutputStream around CBZip2OutputStream) whose close ordering is wrong; code that reuses a stream variable after a try-with-resources block; concurrent close/write without synchronization; frameworks calling close on error paths while another thread flushes the last byte.

Related errors


AI-assisted analysis of apache/hadoop@2add963021 (2026-08-22). Data as JSON: /api/errors/ea41251e4a89adf4. Report an issue: GitHub.