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

  1. Log the cause (IOException.getCause()) to find the real reason (reset by peer, response ended, etc.)
  2. Check response/closed state and stop streaming when the client disconnects instead of continuing to write
  3. Reduce chunk size or apply backpressure so the write queue is not overwhelmed
  4. 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

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


AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05). Data as JSON: /api/errors/41e5426475cc6d5d. Report an issue: GitHub.