eclipse-vertx/vert.x · error · IllegalStateException
Request must have a valid content-type header to decode a mu
Error message
Request must have a valid content-type header to decode a multipart request
What it means
setExpectMultipart(true) validates the Content-Type header via HttpUtils.isValidMultipartContentType before creating the Netty multipart decoder. If the header exists but is not multipart/form-data (or a valid multipart variant), an IllegalStateException is thrown because the body cannot be decoded as multipart.
Source
Thrown at vertx-core/src/main/java/io/vertx/core/http/impl/HttpServerRequestImpl.java:418
@Override
public Future<NetSocket> toNetSocket() {
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;View on GitHub (pinned to fb308bd8c3)
Solutions
- Send the request with Content-Type: multipart/form-data; boundary=<boundary>
- Only call setExpectMultipart(true) when the request's Content-Type indicates multipart
- Inspect request.getHeader("Content-Type") and route to a JSON/form decoder instead when it isn't multipart
Example fix
// before
request.setExpectMultipart(true); // throws for application/json
// after
String ct = request.getHeader("Content-Type");
if (ct != null && ct.toLowerCase().startsWith("multipart/form-data")) {
request.setExpectMultipart(true);
} else {
// handle other body types
} Defensive patterns
Strategy: validation
Validate before calling
String ct = request.getHeader(HttpHeaders.CONTENT_TYPE);
if (ct == null || !ct.toLowerCase().startsWith("multipart/form-data")) {
request.response().setStatusCode(415).end();
return;
}
request.setExpectMultipart(true); Try / catch
try {
request.setExpectMultipart(true);
} catch (IllegalStateException e) {
// content type not multipart; use another decoder
} Prevention
- Only enable multipart for multipart/form-data requests
- Dispatch decoders based on Content-Type
- Ensure clients include the boundary parameter
When it happens
Trigger: Calling request.setExpectMultipart(true) when the Content-Type is present but not multipart, e.g. application/json, application/x-www-form-urlencoded, text/plain.
Common situations: Enabling multipart unconditionally for all POST routes including JSON APIs; clients mislabeling the content type; forgetting the boundary parameter in the content type.
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
- Multipart form requires multipart/form-data content type ins
- Request method must be one of POST, PUT, PATCH or DELETE to
- Request must have a valid content-type header to decode a mu
- keepAliveTimeout must be >= 0
AI-assisted analysis of eclipse-vertx/vert.x@fb308bd8c3 (2026-09-06).
Data as JSON: /api/errors/99d8ff7e36a480b4.
Report an issue: GitHub.