eclipse-vertx/vert.x · error · IllegalStateException
Request method must be one of POST, PUT, PATCH or DELETE to
Error message
Request method must be one of POST, PUT, PATCH or DELETE to decode a multipart request
What it means
Multipart decoding via setExpectMultipart(true) is only supported for methods with a body semantics — POST, PUT, PATCH, DELETE (validated by HttpUtils.isValidMultipartMethod). Using it on GET, HEAD, OPTIONS, etc. throws IllegalStateException because those requests normally carry no multipart body.
Source
Thrown at vertx-core/src/main/java/io/vertx/core/http/impl/HttpServerRequestImpl.java:421
return response.netSocket(this);
}
@Override
public HttpServerRequest setExpectMultipart(boolean expect) {
synchronized (connection) {
checkEnded();
expectMultipart = expect;
if (expect) {
if (postRequestDecoder == null) {
String contentType = headersMap.get(HttpHeaderNames.CONTENT_TYPE);
if (contentType == null) {
throw new IllegalStateException("Request must have a content-type header to decode a multipart request");
}
if (!HttpUtils.isValidMultipartContentType(contentType)) {
throw new IllegalStateException("Request must have a valid content-type header to decode a multipart request");
}
if (!HttpUtils.isValidMultipartMethod(method.toNetty())) {
throw new IllegalStateException("Request method must be one of POST, PUT, PATCH or DELETE to decode a multipart request");
}
HttpRequest req = new DefaultHttpRequest(
io.netty.handler.codec.http.HttpVersion.HTTP_1_1,
method.toNetty(),
uri);
req.headers().add(HttpHeaderNames.CONTENT_TYPE, contentType);
NettyFileUploadDataFactory factory = new NettyFileUploadDataFactory(context, this, () -> uploadHandler);
factory.setMaxLimit(maxFormAttributeSize);
postRequestDecoder = new HttpPostRequestDecoder(factory, req, HttpConstants.DEFAULT_CHARSET, maxFormFields, maxFormBufferedBytes);
}
} else {
postRequestDecoder = null;
}
}
return this;
}
@OverrideView on GitHub (pinned to fb308bd8c3)
Solutions
- Send the multipart upload with POST, PUT, PATCH, or DELETE instead of GET
- Guard setExpectMultipart(true) with a method check
- Move file uploads to a POST endpoint
Example fix
// before
router.route("/upload").handler(ctx -> {
ctx.request().setExpectMultipart(true); // throws for GET
});
// after
router.post("/upload").handler(ctx -> {
ctx.request().setExpectMultipart(true);
}); Defensive patterns
Strategy: validation
Validate before calling
HttpMethod m = request.method();
if (m != HttpMethod.POST && m != HttpMethod.PUT && m != HttpMethod.PATCH && m != HttpMethod.DELETE) {
request.response().setStatusCode(405).end();
return;
}
request.setExpectMultipart(true); Try / catch
try {
request.setExpectMultipart(true);
} catch (IllegalStateException e) {
// method not multipart-capable
} Prevention
- Bind multipart handling only to POST/PUT/PATCH/DELETE routes
- Use router.post(...) instead of router.route(...) for upload endpoints
- Upload files with POST, not GET
When it happens
Trigger: Calling request.setExpectMultipart(true) on a GET, HEAD, OPTIONS, or other non POST/PUT/PATCH/DELETE request.
Common situations: Shared middleware that enables multipart on every route including GET endpoints; misconfigured client sending form data with GET; framework routing that applies the same body handling to all methods.
Understand the failure class
Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.
Related errors
- Request must have a content-type header to decode a multipar
- Request must have a valid content-type header to decode a mu
- Request method must be one of POST, PUT, PATCH or DELETE to
- keepAliveTimeout must be >= 0
- maxPoolSize must be > 0
AI-assisted analysis of eclipse-vertx/vert.x@fb308bd8c3 (2026-09-06).
Data as JSON: /api/errors/2e7711da69c650e3.
Report an issue: GitHub.