quarkusio/quarkus · error · IOException
Failed to write
Error message
Failed to write
What it means
VertxOutputStream.write() forwards data to the underlying Vertx HttpServerResponse while holding a lock; any exception raised by the response write (buffer creation, connection reset, response already ended) is wrapped in an IOException with message 'Failed to write'. The ByteBuf is released before throwing to avoid native memory leaks.
Source
Thrown at independent-projects/vertx-utils/src/main/java/io/quarkus/vertx/utils/VertxOutputStream.java:110
if (last && data == null) {
response.end();
return;
}
lock.lock();
try {
awaitWriteable();
if (last) {
if (!response.ended()) { // can happen when an exception occurs during JSON serialization with Jackson
response.end(createBuffer(data));
}
} else {
response.write(createBuffer(data));
}
} catch (Exception e) {
if (data != null && data.refCnt() > 0) {
data.release();
}
throw new IOException("Failed to write", e);
} finally {
lock.unlock();
}
}
private void awaitWriteable() throws IOException {
// is it running in an event loop?
if (Context.isOnEventLoopThread()) {
// NEVER block the event loop!
return;
}
assert lock.isHeldByCurrentThread();
while (response.writeQueueFull()) {
if (throwable != null) {
throw new IOException(throwable);
}
if (response.closed()) {
throw new IOException("Connection has been closed");View on GitHub (pinned to e1c734241f)
Solutions
- Log the cause (IOException.getCause()) to find the real reason (reset by peer, response ended, etc.)
- Check response/closed state and stop streaming when the client disconnects instead of continuing to write
- Reduce chunk size or apply backpressure so the write queue is not overwhelmed
- Ensure writes are not attempted after the response has been ended elsewhere in the handler
Example fix
// before
out.write(chunk); // throws IOException("Failed to write") after client disconnect
// after
if (!context.response().closed() && !context.response().ended()) {
out.write(chunk);
} else {
out.close();
return;
} Defensive patterns
Strategy: try-catch
Try / catch
try {
out.writeBlocking(data);
} catch (IOException e) {
logger.debug("Write failed (client likely disconnected): {}", e.getCause() == null ? e : e.getCause().toString());
try { out.close(); } catch (IOException ignored) { }
} Prevention
- Check response closed/ended state before each chunk
- Keep writes small so the write queue drains between calls
- Log causes at debug level; client disconnects during streaming are routine
When it happens
Trigger: Calling write()/writeBlocking() when the client has disconnected, the response has already ended, the write queue is in a failed state, or the event loop throws while handling the write.
Common situations: Clients aborting large downloads mid-stream; browser timeouts on slow server-sent-event responses; proxy/load-balancer idle timeouts closing the connection while the server is still writing.
Related errors
- Connection has been closed
- Stream is closed
- Failed to write
- Connection has been closed
- Response already committed
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/41e5426475cc6d5d.
Report an issue: GitHub.