quarkusio/quarkus · error · IOException
Stream is closed
Error message
Stream is closed
What it means
VertxClientInputStream.read throws IOException("Stream is closed") when the response body stream has already been closed and read() is called again. This is standard InputStream closed-stream semantics: once the client response (and its underlying Netty connection buffer) is released, further reads are illegal.
Source
Thrown at independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/handlers/VertxClientInputStream.java:49
@Override
public int read() throws IOException {
byte[] b = new byte[1];
int read = read(b);
if (read == -1) {
return -1;
}
return b[0] & 0xff;
}
@Override
public int read(final byte[] b) throws IOException {
return read(b, 0, b.length);
}
@Override
public int read(final byte[] b, final int off, final int len) throws IOException {
if (closed) {
throw new IOException("Stream is closed");
}
readIntoBuffer();
if (finished) {
return -1;
}
if (len == 0) {
return 0;
}
ByteBuf buffer = pooled;
int copied = Math.min(len, buffer.readableBytes());
buffer.readBytes(b, off, copied);
if (!buffer.isReadable()) {
pooled.release();
pooled = null;
}
return copied;
}
View on GitHub (pinned to e1c734241f)
Solutions
- Read the entity fully before closing the Response / leaving the try-with-resources block.
- Do not read the entity stream twice — buffer it (e.g. readAllBytes()) if the content is needed more than once.
- Avoid caching the InputStream beyond the response lifecycle; copy to a ByteArrayOutputStream if needed later.
- If the stream closes unexpectedly mid-read, check connection timeouts/idle settings on the REST client config.
Example fix
// before
byte[] data;
try (Response res = client.get()) {
data = null;
}
data = res.readEntity(InputStream.class).readAllBytes(); // closed
// after
byte[] data;
try (Response res = client.get()) {
data = res.readEntity(InputStream.class).readAllBytes();
} Defensive patterns
Strategy: try-catch
Try / catch
byte[] data;
try (Response res = client.target(uri).request().get()) {
try (InputStream in = res.readEntity(InputStream.class)) {
data = in.readAllBytes();
}
} catch (IOException e) {
if ("Stream is closed".equals(e.getMessage())) {
// re-issue the request; never reuse the cached stream
data = reissueRequest();
} else { throw new UncheckedIOException(e); }
} Prevention
- Consume the body inside the response's try-with-resources scope
- Never read the entity stream twice or cache the InputStream
- Copy needed bytes to a byte[]/file before closing the response
When it happens
Trigger: Calling read() on the Response.readEntity() stream after the response was closed, after the connection was returned to the pool, double-consuming the entity (read twice), or reading after try-with-resources closed the Response.
Common situations: Caching the InputStream and reading it later outside the request scope; closing the response in a finally block then using the stream; concurrent reads of the same response body from multiple threads; timeouts that close the connection mid-read.
Related errors
- Stream is closed
- Entity stream has already been read and is not buffered: cal
- Error reading stream.
- RestClientProxy is closed
- The Reactive REST Client needs to be built within the contex
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/59756f55b2d62974.
Report an issue: GitHub.