{"record":{"id":"a1687147ae7de3a8","repo":"apache/hadoop","slug":"stream-closed-a16871","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/fs/ftp/FTPInputStream.java","lineNumber":73,"sourceCode":"  public long getPos() throws IOException {\n    return pos;\n  }\n\n  // We don't support seek.\n  @Override\n  public void seek(long pos) throws IOException {\n    throw new IOException(\"Seek not supported\");\n  }\n\n  @Override\n  public boolean seekToNewSource(long targetPos) throws IOException {\n    throw new IOException(\"Seek not supported\");\n  }\n\n  @Override\n  public synchronized int read() throws IOException {\n    if (closed) {\n      throw new IOException(\"Stream closed\");\n    }\n\n    int byteRead = wrappedStream.read();\n    if (byteRead >= 0) {\n      pos++;\n    }\n    if (stats != null && byteRead >= 0) {\n      stats.incrementBytesRead(1);\n    }\n    return byteRead;\n  }\n\n  @Override\n  public synchronized int read(byte buf[], int off, int len) throws IOException {\n    if (closed) {\n      throw new IOException(\"Stream closed\");\n    }\n","sourceCodeStart":55,"sourceCodeEnd":91,"githubUrl":"https://github.com/apache/hadoop/blob/2add9630210752f88ceb1bb74eb65e37bf41da8e/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/ftp/FTPInputStream.java#L55-L91","documentation":"The single-byte read() checks the wrapper's closed flag, which close() sets before releasing resources; any read after close throws IOException(\"Stream closed\"). The check is purely on the wrapper — the underlying FTP data stream is already gone at that point.","triggerScenarios":"read() after close() in the same thread (finally-block ordering bug); a second consumer reading a stream the first consumer closed; a watchdog/cleanup thread closing streams still being drained by a reader thread.","commonSituations":"try-with-resources scope mistakes where parsing happens after the try block; frameworks closing input on task cancellation while a reader loop still drains; sharing one open stream across map tasks or threads.","solutions":["Move every read inside the stream's lifecycle scope (try-with-resources block)","Enforce single ownership: one reader per stream; pass Paths between components, not open streams","For shared streams, synchronize close with readers (or use an external closed flag) so close waits for the read loop","Reopen a fresh stream from the FileSystem if data must be read again"],"exampleFix":"// before\nFSDataInputStream in = fs.open(path);\nin.close();\nint b = in.read();          // IOException: Stream closed\n\n// after\ntry (FSDataInputStream in = fs.open(path)) {\n  int b = in.read();        // all reads inside the scope\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"catch IOException from read() and treat \"Stream closed\" as a lifecycle bug in your code (not a data error) — locate the premature close rather than retrying the read.","preventionTips":["Use try-with-resources so the read scope cannot outlive the stream","Pass Paths between components, never open streams","Null the stream reference right after close so late readers fail on a null check"],"tags":["ftp","hadoop","input-stream","lifecycle","use-after-close"],"backgroundTag":"stream-closed","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-23T01:17:44.959Z"}