{"record":{"id":"a8b91d17af6542c1","repo":"apache/hadoop","slug":"stream-closed-a8b91d","errorCode":null,"errorMessage":"stream closed","messagePattern":"stream closed","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/io/compress/bzip2/CBZip2OutputStream.java","lineNumber":873,"sourceCode":"  public final int getBlockSize() {\n    return this.blockSize100k;\n  }\n\n  @Override\n  public void write(final byte[] buf, int offs, final int len)\n      throws IOException {\n    if (offs < 0) {\n      throw new IndexOutOfBoundsException(\"offs(\" + offs + \") < 0.\");\n    }\n    if (len < 0) {\n      throw new IndexOutOfBoundsException(\"len(\" + len + \") < 0.\");\n    }\n    if (offs + len > buf.length) {\n      throw new IndexOutOfBoundsException(\"offs(\" + offs + \") + len(\"\n          + len + \") > buf.length(\" + buf.length + \").\");\n    }\n    if (this.out == null) {\n      throw new IOException(\"stream closed\");\n    }\n\n    for (int hi = offs + len; offs < hi;) {\n      write0(buf[offs++]);\n    }\n  }\n\n  private void write0(int b) throws IOException {\n    if (this.currentChar != -1) {\n      b &= 0xff;\n      if (this.currentChar == b) {\n        if (++this.runLength > 254) {\n          writeRun();\n          this.currentChar = -1;\n          this.runLength = 0;\n        }\n        // else nothing to do\n      } else {","sourceCodeStart":855,"sourceCodeEnd":891,"githubUrl":"https://github.com/apache/hadoop/blob/2add9630210752f88ceb1bb74eb65e37bf41da8e/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/io/compress/bzip2/CBZip2OutputStream.java#L855-L891","documentation":"After passing argument validation, CBZip2OutputStream.write(byte[], offs, len) checks the lifecycle: once close() has run, this.out is null and the method throws IOException(\"stream closed\") instead of writing. The compressor is single-use; all data must be written before close. (Note the sibling single-byte write() throws the shorter message \"closed\" — same condition.)","triggerScenarios":"Calling write(byte[], offs, len) on a CBZip2OutputStream after close(): output moved/rotated and a late buffer flushed by a wrapper, error paths that closed the stream then continued, or two components both writing to a stream one of them already closed.","commonSituations":"Wrapped streams (DataOutputStream/CountingOutputStream over CBZip2OutputStream) flushing buffered data during their own close() after the inner bzip2 stream was closed first; scheduled/async flush tasks surviving past file close; MapReduce/Hive output committers closing streams before a final empty-buf write; retry logic re-entering a write loop after cleanup.","solutions":["Order closes outside-in: write everything, close the outer wrapper (which flushes), let it close the CBZip2OutputStream — never close the inner stream manually when it is wrapped.","Guard with an application-level closed flag checked before each write batch.","Cancel or join any async flusher/scheduler threads before closing the stream.","Make error paths idempotent: close exactly once (e.g. via try-with-resources) and stop producing after an exception."],"exampleFix":"// before\nDataOutputStream dos = new DataOutputStream(cbz);\ncbz.close();      // inner stream closed first\ndos.writeInt(x);  // flush later hits IOException: stream closed\n\n// after\ntry (DataOutputStream dos = new DataOutputStream(\n        new CBZip2OutputStream(out))) {\n  dos.writeInt(x);\n} // wrapper flushes, then closes cbz exactly once","handlingStrategy":"try-catch","validationCode":"private final AtomicBoolean closed = new AtomicBoolean(false);\n\nvoid writeAll(byte[] b, int off, int len) throws IOException {\n  if (closed.get()) throw new IllegalStateException(\"stream already closed\");\n  cbz.write(b, off, len);\n}","typeGuard":null,"tryCatchPattern":"try {\n  cbz.write(buf, off, len);\n} catch (IOException e) {\n  if (\"stream closed\".equals(e.getMessage())) {\n    // lifecycle bug: a wrapper flushed after close; fix close ordering\n    throw new IllegalStateException(\"write after close (wrapper flush order)\", e);\n  }\n  throw e;\n}","preventionTips":["Close outside-in: let the outer wrapper's close flush into the still-open CBZip2OutputStream.","Cancel async flushers before closing output files.","Never close the inner bzip2 stream manually when it is wrapped."],"tags":["bzip2","compression","write-after-close","lifecycle","hadoop"],"backgroundTag":"write-after-close","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-22T20:17:22.307Z"}