apache/hadoop · error · IOException
Stream closed
Error message
Stream closed
What it means
ByteRangeInputStream (the base of WebHdfsFileSystem.OffsetUrlInputStream, i.e., every WebHDFS/SWebHDFS FSDataInputStream over HTTP) is a state machine with StreamStatus NORMAL/SEEK/CLOSED. close() sets status=CLOSED; any later read()/available() calls getInputStream(), which throws this IOException. It is the HTTP equivalent of reading a stream after close() — the object cannot be reopened, you must call FileSystem.open() again.
Source
Thrown at hadoop-hdfs-project/hadoop-hdfs-client/src/main/java/org/apache/hadoop/hdfs/web/ByteRangeInputStream.java:124
protected abstract URL getResolvedUrl(final HttpURLConnection connection
) throws IOException;
@VisibleForTesting
protected InputStream getInputStream() throws IOException {
switch (status) {
case NORMAL:
break;
case SEEK:
if (in != null) {
in.close();
}
InputStreamAndFileLength fin = openInputStream(startPos);
in = fin.in;
fileLength = fin.length;
status = StreamStatus.NORMAL;
break;
case CLOSED:
throw new IOException("Stream closed");
}
return in;
}
@VisibleForTesting
protected InputStreamAndFileLength openInputStream(long startOffset)
throws IOException {
if (startOffset < 0) {
throw new EOFException("Negative Position");
}
// Use the original url if no resolved url exists, eg. if
// it's the first time a request is made.
final boolean resolved = resolvedURL.getURL() != null;
final URLOpener opener = resolved? resolvedURL: originalURL;
final HttpURLConnection connection = opener.connect(startOffset, resolved);
resolvedURL.setURL(getResolvedUrl(connection));
View on GitHub (pinned to 2add963021)
Solutions
- Move all reads inside the stream's owning scope (try-with-resources block) so nothing reads after close
- If the stream is shared, give it exactly one owner responsible for close, or wrap it in an uncloseable filter (CloseShieldInputStream) for secondary readers
- Reopen with fs.open(path) when data is still needed after close
Example fix
// before
try (FSDataInputStream in = fs.open(path)) {
in.read(buf);
}
long skipped = in.read(); // IOException: Stream closed
// after
try (FSDataInputStream in = fs.open(path)) {
in.read(buf);
long extra = in.read(); // stays inside the owning scope
} Defensive patterns
Strategy: validation
Validate before calling
// wrap shared streams so secondary readers cannot close the primary InputStream shared = org.apache.commons.io.input.CloseShieldInputStream.wrap(fs.open(path));
Try / catch
try {
int b = in.read();
} catch (IOException e) {
if ("Stream closed".equals(e.getMessage())) {
// lifecycle bug in caller code: reopen, do not retry the dead handle
try (FSDataInputStream fresh = fs.open(path)) { /* reread */ }
} else { throw e; }
} Prevention
- Own every stream in exactly one try-with-resources scope
- Null the reference after close so accidental reuse fails fast as NPE
- Use CloseShieldInputStream for observability/metrics wrappers that must not close the underlying stream
When it happens
Trigger: Call read(), read(byte[],int,int), or available() on a WebHDFS FSDataInputStream after close() — e.g., reading in a finally block after a try-with-resources block already closed it, or keeping a cached stream handle past its consumer's lifetime.
Common situations: try-with-resources that closes the stream while a helper (checksum computation, logging, metrics) still reads from it; sharing one open stream across components where one closes it; double-ownership of streams in wrappers. close() itself is safe to call twice — only subsequent reads fail.
Related errors
AI-assisted analysis of apache/hadoop@2add963021 (2026-08-22).
Data as JSON: /api/errors/75755b41079ad057.
Report an issue: GitHub.