apache/hadoop · error · IOException
Stream closed
Error message
Stream closed
What it means
readWithStrategy() first calls dfsClient.checkOpen() and then tests the stream's closed flag; any read attempted after close() throws this IOException. It is a pure use-after-close lifecycle bug on the caller side (or a FileSystem closed underneath the stream), not a cluster condition.
Source
Thrown at hadoop-hdfs-project/hadoop-hdfs-client/src/main/java/org/apache/hadoop/hdfs/DFSInputStream.java:868
String msg = String.format("Failed to read from all available datanodes for file %s "
+ "at position=%d after retrying.", src, position);
DFSClient.LOG.error(msg);
for (Map.Entry<InetSocketAddress, List<IOException>> dataNodeExceptions :
exceptionMap.entrySet()) {
List<IOException> exceptions = dataNodeExceptions.getValue();
for (IOException ex : exceptions) {
msg = String.format("Exception when fetching file %s at position=%d at datanode %s:", src,
position, dataNodeExceptions.getKey());
DFSClient.LOG.error(msg, ex);
}
}
}
protected synchronized int readWithStrategy(ReaderStrategy strategy)
throws IOException {
dfsClient.checkOpen();
if (closed.get()) {
throw new IOException("Stream closed");
}
int len = strategy.getTargetLength();
CorruptedBlocks corruptedBlocks = new CorruptedBlocks();
// A map to record IOExceptions when fetching from each datanode. Key is the socketAddress of
// a datanode.
Map<InetSocketAddress, List<IOException>> exceptionMap = new HashMap<>();
failures = 0;
maybeRegisterBlockRefresh();
if (pos < getFileLength()) {
int retries = 2;
while (retries > 0) {
try {
// currentNode can be left as null if previous read had a checksum
// error on the same block. See HDFS-3067
if (pos > blockEnd || currentNode == null) {View on GitHub (pinned to 2add963021)
Solutions
- Own the stream in exactly one place; close it once, after all reads finish
- Use try-with-resources around the whole read lifetime, not around a producer that hands the stream out
- Do not close shared FileSystem instances (FileSystem.get caches per URI); use IOUtils.closeStream in finally on streams only
Example fix
// before
FSDataInputStream in = fs.open(path);
readHeader(in);
in.close();
readBody(in); // throws "Stream closed"
// after: keep the stream open for its whole use, close once
try (FSDataInputStream in = fs.open(path)) {
readHeader(in);
readBody(in);
} Defensive patterns
Strategy: validation
Validate before calling
// one-owner wrapper that makes the lifecycle explicit at the call site
final class GuardedReader implements Closeable {
private final FSDataInputStream in;
private volatile boolean closed;
GuardedReader(FileSystem fs, Path p) throws IOException { in = fs.open(p); }
int read(byte[] b) throws IOException {
if (closed) throw new IllegalStateException("reader closed");
return in.read(b);
}
public synchronized void close() throws IOException {
if (!closed) { closed = true; in.close(); }
}
} Type guard
static boolean isUseAfterClose(IOException e) {
return e.getMessage() != null && e.getMessage().equals("Stream closed");
} Try / catch
try {
return in.read(buf);
} catch (IOException e) {
if (isUseAfterClose(e)) throw new IllegalStateException("bug: read after close", e);
throw e;
} Prevention
- Close each stream exactly once, from its single owner, after all reads complete
- Use try-with-resources spanning the entire read lifetime
- Never close shared FileSystem objects while cached streams are in use
When it happens
Trigger: Calling read() after close() on the same FSDataInputStream; a wrapper/decoder stream closing the underlying stream early; closing the shared FileSystem while cached streams are still being read (checkOpen also fires when the client is shut down).
Common situations: Two components sharing one stream where one closes it; try-with-resources nesting mistakes; frameworks caching FileSystem instances and closing them per-job instead of per-user/VM.
Related errors
- Filesystem closed
- Stream closed
- Credentials requested after provider list was closed
- Stream is closed!
- Stream closed
AI-assisted analysis of apache/hadoop@2add963021 (2026-08-22).
Data as JSON: /api/errors/05b4c46b83882498.
Report an issue: GitHub.