{"record":{"id":"9a76caefe7a9a9ea","repo":"apache/hadoop","slug":"key-stream-is-closed","errorCode":null,"errorMessage":"key + \": Stream is closed!\"","messagePattern":"key \\+ \": Stream is closed!\"","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"hadoop-cloud-storage-project/hadoop-bos/src/main/java/org/apache/hadoop/fs/bos/BosInputStream.java","lineNumber":340,"sourceCode":"  public synchronized void setReadahead(Long readahead) {\n    if (readahead == null) {\n      this.readahead = DEFAULT_READAHEAD_LEN;\n    } else {\n      this.readahead = Math.max(\n          readahead, DEFAULT_READAHEAD_LEN);\n    }\n  }\n\n  /**\n   * Verify that the input stream is open. Non blocking; this\n   * gives the last state of the volatile {@link #closed}\n   * field.\n   *\n   * @throws IOException if the connection is closed.\n   */\n  private void checkNotClosed() throws IOException {\n    if (closed) {\n      throw new IOException(\n          key + \": \"\n              + FSExceptionMessages.STREAM_IS_CLOSED);\n    }\n  }\n\n  /**\n   * Perform lazy seek and adjust stream to correct position\n   * for reading.\n   *\n   * @param targetPos position from where data should be read\n   * @param len length of the content that needs to be read\n   * @throws IOException if an I/O error occurs\n   */\n  private void lazySeek(long targetPos, long len)\n      throws IOException {\n    // For lazy seek\n    try {\n      seekInStream(targetPos, len);","sourceCodeStart":322,"sourceCodeEnd":358,"githubUrl":"https://github.com/apache/hadoop/blob/2add9630210752f88ceb1bb74eb65e37bf41da8e/hadoop-cloud-storage-project/hadoop-bos/src/main/java/org/apache/hadoop/fs/bos/BosInputStream.java#L322-L358","documentation":"Every public operation on BosInputStream starts with checkNotClosed(); once the volatile closed flag is set — by close() or by internal failure paths such as closeStream('native store retrieve failed') — any further read/seek throws IOException '<key>: Stream is closed'. The message includes the object key so you can identify which stream was used after close.","triggerScenarios":"Calling read/seek/available after close(); continuing to use a stream whose earlier read already failed (internal recovery closes it); two threads sharing a stream where one closes it while the other reads.","commonSituations":"try-with-resources scope wrapped too wide, so a helper still holds the stream when the block exits; error paths that half-consume the stream and then continue processing; frameworks that pool or hand off streams across close boundaries.","solutions":["Narrow try-with-resources (or finally-close) scope to exactly the code that reads","After any IOException from a read, discard the stream and open a new one — internal failures mark it closed","Give the stream a single owner for its full lifecycle; do not share across threads"],"exampleFix":"// before\ntry (FSDataInputStream in = fs.open(p)) {\n  return parse(in); // parse also called later with closed stream\n}\nparse(cachedIn); // reused after close\n\n// after: open per consumer\ntry (FSDataInputStream in = fs.open(p)) {\n  return parse(in);\n}","handlingStrategy":"validation","validationCode":"// track ownership instead of probing the stream\nboolean readDone = false;\ntry (FSDataInputStream in = fs.open(p)) {\n  readDone = consume(in);\n} // nothing touches in after this block","typeGuard":"static boolean isStreamClosedMessage(IOException e) {\n  return e.getMessage() != null && e.getMessage().endsWith(\"Stream is closed\");\n}","tryCatchPattern":"catch (IOException e) {\n  if (isStreamClosedMessage(e)) {\n    in = fs.open(path); // stream died earlier: reopen, do not reuse\n    in.seek(lastGoodPos);\n  } else { throw e; }\n}","preventionTips":["Scope try-with-resources to exactly the reading code","Treat any prior read IOException as fatal for that stream instance","One owner thread per stream for its whole lifecycle"],"tags":["bos","input-stream","stream-closed","lifecycle","hadoop"],"backgroundTag":"io-stream-closed","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-22T20:17:22.307Z"}