apache/flink · error · IOException

Stream closed.

Error message

Stream closed.

What it means

Thrown by RefCountedFileWithStream.requireOpened() when a write/flush/getPos operation is attempted on a reference-counted temp file+stream combo whose `closed` flag is true. This wraps the underlying OutputStream along with the ref-counted file.

Source

Thrown at flink-core/src/main/java/org/apache/flink/core/fs/RefCountedFileWithStream.java:72

            stream.write(b, off, len);
        }
    }

    void flush() throws IOException {
        requireOpened();
        stream.flush();
    }

    void closeStream() {
        if (!closed) {
            IOUtils.closeQuietly(stream);
            closed = true;
        }
    }

    private void requireOpened() throws IOException {
        if (closed) {
            throw new IOException("Stream closed.");
        }
    }

    // ------------------------------ Factory methods for initializing a temporary file
    // ------------------------------

    public static RefCountedFileWithStream newFile(final File file, final OutputStream currentOut)
            throws IOException {
        return new RefCountedFileWithStream(file, currentOut, 0L);
    }

    public static RefCountedFileWithStream restoredFile(
            final File file, final OutputStream currentOut, final long bytesInCurrentPart) {
        return new RefCountedFileWithStream(file, currentOut, bytesInCurrentPart);
    }
}

View on GitHub (pinned to 2f3c205e92)

Solutions

  1. Ensure all writes complete before closeStream(); reorder so cleanup is last.
  2. Null out the stream reference after close and guard subsequent access.
  3. Use try-with-resources or a dedicated closeable lifecycle.
  4. In error handlers, branch on a 'closed' flag to avoid post-close writes.
Defensive patterns

Strategy: validation

Validate before calling

void safeWrite(RefCountedFileWithStream s, byte[] b) throws IOException {
    if (s.isClosed()) return;
    s.write(b);
}

Try / catch

try {
    s.write(buf);
} catch (IOException e) {
    if ("Stream closed.".equals(e.getMessage())) return;
    throw e;
}

Prevention

When it happens

Trigger: Calling write/flush on a RefCountedFileWithStream after closeStream() was invoked (either directly or via final release).

Common situations: Sink writer error paths that close the stream then a finally block tries to flush; double-cleanup during task failure; test harness closing too early.

Related errors


AI-assisted analysis of apache/flink@2f3c205e92 (2026-08-14). Data as JSON: /api/errors/9007678ab5dc2c8f. Report an issue: GitHub.