eclipse-vertx/vert.x · error · IllegalStateException

Request must have a content-type header to decode a multipar

Error message

Request must have a content-type header to decode a multipart request

What it means

setExpectMultipart(true) tells Vert.x to decode the request body as multipart/form-data using a Netty PostRequestDecoder. Multipart decoding requires the request to declare its content type; if the Content-Type header is absent, the decoder cannot know the body format, so an IllegalStateException is thrown.

Source

Thrown at vertx-core/src/main/java/io/vertx/core/http/impl/HttpServerRequestImpl.java:415

      return absoluteURI;
    }
  }

  @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;

View on GitHub (pinned to fb308bd8c3)

Solutions

  1. Ensure the HTTP client sends a Content-Type header, e.g. multipart/form-data; boundary=...
  2. Validate the header server-side before calling setExpectMultipart(true)
  3. If the request is legitimately not multipart, do not enable multipart expectation for it

Example fix

// before
request.setExpectMultipart(true); // throws when no Content-Type

// after
if (request.getHeader("Content-Type") != null) {
  request.setExpectMultipart(true);
} else {
  request.response().setStatusCode(400).end("Content-Type header required");
}
Defensive patterns

Strategy: validation

Validate before calling

if (request.getHeader(HttpHeaders.CONTENT_TYPE) == null) {
  request.response().setStatusCode(400).end();
  return;
}
request.setExpectMultipart(true);

Try / catch

try {
  request.setExpectMultipart(true);
} catch (IllegalStateException e) {
  // missing content-type; reject request
}

Prevention

When it happens

Trigger: Calling request.setExpectMultipart(true) on an incoming request that has no Content-Type header at all.

Common situations: Clients (curl, custom HTTP clients, tests) sending a multipart-looking body without setting Content-Type; proxies stripping headers; requests where the body was sent raw without headers.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


AI-assisted analysis of eclipse-vertx/vert.x@fb308bd8c3 (2026-09-06). Data as JSON: /api/errors/45acf85a154ca204. Report an issue: GitHub.