quarkusio/quarkus · error · IllegalStateException

Response head already sent with chunked=${response.isChunked

Error message

Response head already sent with chunked=${response.isChunked()}, cannot change to chunked=${chunked}

What it means

VertxResteasyReactiveRequestContext.setChunked() throws IllegalStateException when the response head has already been sent and the requested chunked flag differs from the chunked value already committed in the response head. HTTP headers (including Transfer-Encoding: chunked) cannot be changed after the head is written.

Source

Thrown at independent-projects/resteasy-reactive/server/vertx/src/main/java/org/jboss/resteasy/reactive/server/vertx/VertxResteasyReactiveRequestContext.java:488

    @Override
    public boolean closed() {
        return response.ended() || response.closed();
    }

    @Override
    public ServerHttpResponse setChunked(boolean chunked) {
        if (!response.headWritten()) {
            try {
                response.setChunked(chunked);
            } catch (IllegalStateException e) {
                // TOCTOU: head was concurrently written between our check and setChunked();
                // verify the already-sent value matches what we wanted to set
                if (response.isChunked() != chunked) {
                    throw e;
                }
            }
        } else if (response.isChunked() != chunked) {
            throw new IllegalStateException(
                    "Response head already sent with chunked=" + response.isChunked()
                            + ", cannot change to chunked=" + chunked);
        }
        return this;
    }

    @Override
    public ServerHttpResponse write(byte[] data, Consumer<Throwable> asyncResultHandler) {
        response.write(Buffer.buffer(data)).onComplete(event -> {
            if (event.failed()) {
                asyncResultHandler.accept(event.cause());
            } else {
                asyncResultHandler.accept(null);
            }
        });
        return this;
    }

View on GitHub (pinned to e1c734241f)

Solutions

  1. Call setChunked() before any response data is written (before the head is flushed).
  2. Make the chunked decision consistent in one place — don't mix a chunked writer with a content-length based write.
  3. Inspect interceptors/filters/writers for a path that writes the response head earlier than expected.

Example fix

// before
response.write(data); // head flushed chunked=false
context.setChunked(true); // IllegalStateException
// after
context.setChunked(true);
response.write(data);
Defensive patterns

Strategy: validation

Validate before calling

if (context.serverResponse().headWritten()) {
    throw new IllegalStateException("Response head already written; cannot change chunked mode");
}
context.setChunked(true);

Try / catch

try {
    context.setChunked(true);
} catch (IllegalStateException e) {
    // head already committed with different chunked flag; leave as-is
}

Prevention

When it happens

Trigger: Calling setChunked(true/false) after the response head was written with the opposite chunked setting — e.g. mixing streaming (chunked) responses with content-length writes, or setting chunked after partial response output.

Common situations: Custom message body writers or filters that toggle chunked mode after another component started writing the response; returning a StreamingOutput after headers were flushed; double-write bugs in interceptors.

Related errors


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