{"record":{"id":"20caea06231fa60d","repo":"eclipse-vertx/vert.x","slug":"request-has-already-been-read-20caea","errorCode":null,"errorMessage":"Request has already been read","messagePattern":"Request has already been read","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"vertx-core/src/main/java/io/vertx/core/http/impl/http1/Http1ServerRequest.java","lineNumber":661,"sourceCode":"    }\n    if (handler != null) {\n      handler.handleException(t);\n    }\n  }\n\n  private void reportRequestReset(Throwable err) {\n    if (conn.httpMetrics != null) {\n      conn.httpMetrics.requestReset(metric);\n    }\n    VertxTracer tracer = context.tracer();\n    if (tracer != null) {\n      tracer.sendResponse(context, null, trace, err, TagExtractor.empty());\n    }\n  }\n\n  private void checkEnded() {\n    if (isEnded()) {\n      throw new IllegalStateException(\"Request has already been read\");\n    }\n  }\n\n  private MultiMap attributes() {\n    // Create it lazily\n    if (attributes == null) {\n      attributes = MultiMap.caseInsensitiveMultiMap();\n    }\n    return attributes;\n  }\n\n  @Override\n  public HttpServerRequest streamPriorityHandler(Handler<StreamPriority> handler) {\n    return this;\n  }\n\n  @Override\n  public DecoderResult decoderResult() {","sourceCodeStart":643,"sourceCodeEnd":679,"githubUrl":"https://github.com/eclipse-vertx/vert.x/blob/fb308bd8c3f12c79f4ae89bef67fadf6c80d036e/vertx-core/src/main/java/io/vertx/core/http/impl/http1/Http1ServerRequest.java#L643-L679","documentation":"Thrown by checkEnded() in Http1ServerRequest whenever a request accessor (setExpectMultipart, body handlers, attributes, etc.) is invoked after the request has already been fully read/ended. Vert.x treats the request as a one-shot stream: once ended, its state can no longer be mutated.","triggerScenarios":"Calling setExpectMultipart(true) or other request configuration after endHandler/body completion has fired, e.g. configuring the request from the response end handler or a later callback.","commonSituations":"Reading the body once with bodyHandler and then calling setExpectMultipart; async callback ordering where the body already completed before configuration code runs.","solutions":["Call setExpectMultipart(true) at the very start of the request handler, before any body read","Only configure the request in the request handler, not in end/close callbacks","Use request.body() (Future-based) once and reuse the resulting Buffer instead of mixing body handlers and configuration calls"],"exampleFix":"// before\nrequest.bodyHandler(b -> { ... });\nrequest.setExpectMultipart(true);\n// after\nrequest.setExpectMultipart(true);\nrequest.bodyHandler(b -> { ... });","handlingStrategy":"validation","validationCode":"if (!request.isEnded()) {\n  request.setExpectMultipart(true);\n}","typeGuard":null,"tryCatchPattern":"try { request.setExpectMultipart(true); } catch (IllegalStateException e) { /* already read: use buffered body */ }","preventionTips":["Configure the request at the top of its handler","Never configure the request from end/close callbacks","Read the body only once per request"],"tags":["http","lifecycle","state","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"}