{"record":{"id":"a5dc72c4c34435ad","repo":"eclipse-vertx/vert.x","slug":"request-has-already-been-read","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/HttpServerRequestImpl.java","lineNumber":239,"sourceCode":"    if (handler != null) {\n      handler.handleEnd();\n    }\n  }\n\n  public void handleReset(long errorCode) {\n    boolean notify;\n    synchronized (connection) {\n      notify = !ended;\n    }\n    if (notify) {\n      notifyException(new StreamResetException(errorCode));\n    }\n    response.handleReset(errorCode);\n  }\n\n  private void checkEnded() {\n    if (ended) {\n      throw new IllegalStateException(\"Request has already been read\");\n    }\n  }\n\n  @Override\n  public HttpMethod method() {\n    return method;\n  }\n\n  @Override\n  public Object metric() {\n    return stream.metric();\n  }\n\n  @Override\n  public ContextInternal context() {\n    return context;\n  }\n","sourceCodeStart":221,"sourceCodeEnd":257,"githubUrl":"https://github.com/eclipse-vertx/vert.x/blob/fb308bd8c3f12c79f4ae89bef67fadf6c80d036e/vertx-core/src/main/java/io/vertx/core/http/impl/HttpServerRequestImpl.java#L221-L257","documentation":"HttpServerRequestImpl.checkEnded() guards all request-reading configuration methods. Once the request body has been fully read (ended == true), mutating stream settings such as handlers, pause/resume, fetch, or enabling multipart parsing is no longer meaningful, so the library throws IllegalStateException to signal the request is consumed.","triggerScenarios":"Calling handler(), pause(), fetch(), endHandler(), setExpectMultipart(true), or uploadHandler() after the request body has already been fully read (end() received / body() or similar already consumed the stream).","commonSituations":"Setting setExpectMultipart(true) inside an endHandler or after awaiting request.body(); configuring handlers after routing middleware already consumed the body; async code that resumes configuration after the body completed.","solutions":["Configure all handlers and setExpectMultipart/uploadHandler immediately when the request arrives, before reading the body","If you need the full body first, don't reconfigure afterwards — operate on the already-read Buffer instead","Restructure async flows so request stream configuration happens synchronously in the request handler, before any await/callback continuation","Wrap configuration in a check: only call these APIs if the request hasn't ended (track it yourself, since ended is private)"],"exampleFix":"// before\nrequest.body().onSuccess(body -> {\n  request.setExpectMultipart(true); // IllegalStateException: already read\n});\n\n// after\nrequest.setExpectMultipart(true); // configure before reading\nrequest.uploadHandler(upload -> { /* ... */ });\nrequest.body().onSuccess(body -> { /* handle decoded body */ });","handlingStrategy":"validation","validationCode":"// Configure everything before reading the body:\nif (!requestHandled) {\n  request.setExpectMultipart(true);\n  request.uploadHandler(u -> {});\n}","typeGuard":null,"tryCatchPattern":"try {\n  request.setExpectMultipart(true);\n} catch (IllegalStateException e) {\n  // request already fully read; handle body elsewhere\n}","preventionTips":["Set all request stream config at the top of the request handler","Never consume the body (body()/endHandler) before configuring multipart/handlers","Keep body reading in one place to avoid hidden early consumption"],"tags":["http","request-body","illegal-state"],"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-14T05:17:10.506Z"}