{"record":{"id":"10a394bee3945849","repo":"eclipse-vertx/vert.x","slug":"response-head-already-sent-10a394","errorCode":null,"errorMessage":"Response head already sent","messagePattern":"Response head already sent","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"vertx-core/src/main/java/io/vertx/core/http/impl/http1/Http1ServerResponse.java","lineNumber":673,"sourceCode":"      closedHandler = this.closeHandler;\n    }\n    if (exceptionHandler != null) {\n      context.dispatch(HttpUtils.CONNECTION_CLOSED_EXCEPTION, exceptionHandler);\n    }\n    if (closedHandler != null) {\n      context.dispatch(null, closedHandler);\n    }\n  }\n\n  private void checkValid() {\n    if (written) {\n      throw new IllegalStateException(RESPONSE_WRITTEN);\n    }\n  }\n\n  private void checkHeadWritten() {\n    if (headWritten) {\n      throw new IllegalStateException(\"Response head already sent\");\n    }\n  }\n\n  private void prepareHeaders(long contentLength) {\n    if (version == HttpVersion.HTTP_1_0 && keepAlive) {\n      headers.set(HttpHeaders.CONNECTION, HttpHeaders.KEEP_ALIVE);\n    } else if (version == HttpVersion.HTTP_1_1 && !keepAlive) {\n      headers.set(HttpHeaders.CONNECTION, HttpHeaders.CLOSE);\n    }\n    if (head || status == HttpResponseStatus.NOT_MODIFIED) {\n      // For HEAD request or NOT_MODIFIED response\n      // don't set automatically the content-length\n      // and remove the transfer-encoding\n      headers.remove(HttpHeaders.TRANSFER_ENCODING);\n    } else {\n      // Set content-length header automatically\n      if (contentLength >= 0 && !headers.contains(HttpHeaders.CONTENT_LENGTH) && !headers.contains(HttpHeaders.TRANSFER_ENCODING)) {\n        headers.set(HttpHeaders.CONTENT_LENGTH, HttpUtils.positiveLongToString(contentLength));","sourceCodeStart":655,"sourceCodeEnd":691,"githubUrl":"https://github.com/eclipse-vertx/vert.x/blob/fb308bd8c3f12c79f4ae89bef67fadf6c80d036e/vertx-core/src/main/java/io/vertx/core/http/impl/http1/Http1ServerResponse.java#L655-L691","documentation":"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\".","triggerScenarios":"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().","commonSituations":"Error-handling code trying to change the status code after a partial body was already written; middleware setting status after the handler flushed headers.","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"],"exampleFix":"// before\nresponse.write(\"partial\");\nresponse.setStatusCode(500);\n// after\nresponse.setStatusCode(500);\nresponse.write(\"partial\");","handlingStrategy":"validation","validationCode":"if (!response.headWritten()) {\n  response.setStatusCode(500);\n}","typeGuard":null,"tryCatchPattern":"try { response.setStatusCode(code); } catch (IllegalStateException e) { /* head already sent */ }","preventionTips":["Set status code and headers before writing the body","Check headWritten() in error handlers","Avoid mutating status after any body write"],"tags":["http","response","headers","http1"],"backgroundTag":"invalid-state-transition","analyzedSha":"fb308bd8c3f12c79f4ae89bef67fadf6c80d036e","analyzedAt":"2026-09-06T11:37:12.241Z","contentChangedAt":"2026-09-06T11:37:12.241Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}