eclipse-vertx/vert.x · error · IllegalStateException
Response head already sent
Error message
Response head already sent
What it means
Thrown by checkHeadWritten() when an operation that must occur before the HTTP head is sent (e.g. setting status code or headers via setStatusCode/putHeader in paths that validate head state) is attempted after headWritten == true. Message: "Response head already sent".
Source
Thrown at vertx-core/src/main/java/io/vertx/core/http/impl/http1/Http1ServerResponse.java:673
closedHandler = this.closeHandler;
}
if (exceptionHandler != null) {
context.dispatch(HttpUtils.CONNECTION_CLOSED_EXCEPTION, exceptionHandler);
}
if (closedHandler != null) {
context.dispatch(null, closedHandler);
}
}
private void checkValid() {
if (written) {
throw new IllegalStateException(RESPONSE_WRITTEN);
}
}
private void checkHeadWritten() {
if (headWritten) {
throw new IllegalStateException("Response head already sent");
}
}
private void prepareHeaders(long contentLength) {
if (version == HttpVersion.HTTP_1_0 && keepAlive) {
headers.set(HttpHeaders.CONNECTION, HttpHeaders.KEEP_ALIVE);
} else if (version == HttpVersion.HTTP_1_1 && !keepAlive) {
headers.set(HttpHeaders.CONNECTION, HttpHeaders.CLOSE);
}
if (head || status == HttpResponseStatus.NOT_MODIFIED) {
// For HEAD request or NOT_MODIFIED response
// don't set automatically the content-length
// and remove the transfer-encoding
headers.remove(HttpHeaders.TRANSFER_ENCODING);
} else {
// Set content-length header automatically
if (contentLength >= 0 && !headers.contains(HttpHeaders.CONTENT_LENGTH) && !headers.contains(HttpHeaders.TRANSFER_ENCODING)) {
headers.set(HttpHeaders.CONTENT_LENGTH, HttpUtils.positiveLongToString(contentLength));View on GitHub (pinned to fb308bd8c3)
Solutions
- Set status code and headers before any write/end call
- Check response.headWritten() before mutating status/headers
- If the head is already out, communicate the failure through the body or close the connection instead
Example fix
// before
response.write("partial");
response.setStatusCode(500);
// after
response.setStatusCode(500);
response.write("partial"); Defensive patterns
Strategy: validation
Validate before calling
if (!response.headWritten()) {
response.setStatusCode(500);
} Try / catch
try { response.setStatusCode(code); } catch (IllegalStateException e) { /* head already sent */ } Prevention
- Set status code and headers before writing the body
- Check headWritten() in error handlers
- Avoid mutating status after any body write
When it happens
Trigger: Calling setStatusCode(), set status/headers-changing APIs guarded by checkHeadWritten(), or sendFile-like paths after the head was flushed by an earlier write()/end()/writeHead().
Common situations: Error-handling code trying to change the status code after a partial body was already written; middleware setting status after the handler flushed headers.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- Response has already been written
- Head already written
- Response has already been written
- a header value contains a prohibited character '127': <value
- a header value must not end with '\r' or '\n':<seq>
AI-assisted analysis of eclipse-vertx/vert.x@fb308bd8c3 (2026-09-06).
Data as JSON: /api/errors/10a394bee3945849.
Report an issue: GitHub.