{"record":{"id":"fff2e89afd9ed9fd","repo":"apache/hadoop","slug":"stream-is-closed-fff2e8","errorCode":null,"errorMessage":"Stream is closed!","messagePattern":"Stream is closed!","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"hadoop-hdfs-project/hadoop-hdfs-client/src/main/java/org/apache/hadoop/hdfs/DFSStripedInputStream.java","lineNumber":363,"sourceCode":"    dfsClient.updateFileSystemReadStats(stats.getNetworkDistance(),\n        stats.getBytesRead(), readTimeMS);\n    assert readStatistics.getBlockType() == BlockType.STRIPED;\n    dfsClient.updateFileSystemECReadStats(stats.getBytesRead());\n  }\n\n  /**\n   * Seek to a new arbitrary location.\n   */\n  @Override\n  public synchronized void seek(long targetPos) throws IOException {\n    if (targetPos > getFileLength()) {\n      throw new EOFException(\"Cannot seek after EOF\");\n    }\n    if (targetPos < 0) {\n      throw new EOFException(\"Cannot seek to negative offset\");\n    }\n    if (closed.get()) {\n      throw new IOException(\"Stream is closed!\");\n    }\n    if (targetPos <= blockEnd) {\n      final long targetOffsetInBlk = getOffsetInBlockGroup(targetPos);\n      if (curStripeRange.include(targetOffsetInBlk)) {\n        int bufOffset = getStripedBufOffset(targetOffsetInBlk);\n        curStripeBuf.position(bufOffset);\n        pos = targetPos;\n        return;\n      }\n    }\n    pos = targetPos;\n    blockEnd = -1;\n  }\n\n  private int getStripedBufOffset(long offsetInBlockGroup) {\n    final long stripeLen = cellSize * dataBlkNum;\n    // compute the position in the curStripeBuf based on \"pos\"\n    return (int) (offsetInBlockGroup % stripeLen);","sourceCodeStart":345,"sourceCodeEnd":381,"githubUrl":"https://github.com/apache/hadoop/blob/2add9630210752f88ceb1bb74eb65e37bf41da8e/hadoop-hdfs-project/hadoop-hdfs-client/src/main/java/org/apache/hadoop/hdfs/DFSStripedInputStream.java#L345-L381","documentation":"DFSStripedInputStream.seek(long) checks an AtomicBoolean 'closed' flag after validating the target position; if the striped input stream has already been closed, it throws IOException('Stream is closed!'). There is no underlying stream left to reposition — the socket and stripe buffers are released by close() — so the only correct response is to open a new stream.","triggerScenarios":"Calling seek() on an FSDataInputStream for an erasure-coded file after close() ran: double-close patterns, seeking in a finally block after an earlier failure closed the stream, or using a stream outside the try-with-resources block that owns it.","commonSituations":"Streams stored in caches/pools and closed by one component while another still seeks; read-retry helpers that close on error and then try to reposition the same instance; large refactors where close() moved into a utility method but callers kept using the stream afterwards.","solutions":["Open a fresh stream with FileSystem.open(path) and seek it to the desired position instead of reusing the closed instance.","Make stream ownership explicit: exactly one owner, try-with-resources at the outermost user, nothing outside the block.","If you cache readers, evict them on close so no caller can obtain a dead stream.","Where late use is legitimate, catch the IOException around seek() and reopen the file transparently."],"exampleFix":"// before\ntry (FSDataInputStream in = fs.open(path)) {\n  process(in);\nin.seek(offset); // stream already closed by try-with-resources\n\n// after\ntry (FSDataInputStream in = fs.open(path)) {\n  process(in);\n  in.seek(offset);\n  readAt(in, offset);\n}","handlingStrategy":"try-catch","validationCode":"DFSInputStream internal = in.getWrappedStream() instanceof DFSInputStream\n    ? (DFSInputStream) in.getWrappedStream() : null;\n// note: isClosed() is package-private; track closure in YOUR code instead\nif (streamClosedFlag.get()) {\n  in = fs.open(path);\n  in.seek(targetPos);\n} else {\n  in.seek(targetPos);\n}","typeGuard":null,"tryCatchPattern":"try {\n  in.seek(targetPos);\n} catch (IOException e) {\n  if (e.getMessage() != null && e.getMessage().contains(\"closed\")) {\n    try (FSDataInputStream fresh = fs.open(path)) {\n      fresh.seek(targetPos);\n      return readFrom(fresh);\n    }\n  }\n  throw e;\n}","preventionTips":["Own the stream in exactly one place: try-with-resources at the outermost consumer; nothing outside it seeks or reads.","For cached streams, evict on close so no caller can get a dead instance.","Never call close() inside helper methods that don't document ownership transfer."],"tags":["hdfs","erasure-coding","input-stream","lifecycle","stream-closed"],"backgroundTag":"stream-already-closed","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-22T20:17:22.307Z"}