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

Thrown by Http1ServerRequest.setExpectMultipart(true) when the request has no Content-Type header. Vert.x needs the content type to decide how to decode the body into multipart/form-data parts via HttpPostRequestDecoder; without it, multipart decoding cannot be configured.

Source

Thrown at vertx-core/src/main/java/io/vertx/core/http/impl/http1/Http1ServerRequest.java:477

          EmptyHttpHeaders.INSTANCE
        );
        conn.createWebSocket(this, promise);
      }
    });
    // In case we were paused
    resume();
  }

  @Override
  public HttpServerRequest setExpectMultipart(boolean expect) {
    synchronized (conn) {
      checkEnded();
      expectMultipart = expect;
      if (expect) {
        if (decoder == null) {
          String contentType = request.headers().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(request.method())) {
            throw new IllegalStateException("Request method must be one of POST, PUT, PATCH or DELETE to decode a multipart request");
          }
          NettyFileUploadDataFactory factory = new NettyFileUploadDataFactory(context, this, () -> uploadHandler);
          factory.setMaxLimit(conn.maxFormAttributeSize());
          int maxFields = conn.maxFormFields();
          int maxBufferedBytes = conn.maxFormBufferedBytes();
          decoder = new HttpPostRequestDecoder(factory, request, HttpConstants.DEFAULT_CHARSET, maxFields, maxBufferedBytes);
        }
      } else {
        decoder = null;
      }
      return this;
    }

View on GitHub (pinned to fb308bd8c3)

Solutions

  1. Set the Content-Type header on the client request, e.g. 'multipart/form-data; boundary=----boundary'
  2. Check the client actually performs a multipart upload rather than sending a raw body without headers
  3. If the body may lack the header, guard the call: only call setExpectMultipart(true) when request.getHeader("Content-Type") != null

Example fix

// before
curl -X POST http://host/upload --data-binary @file.bin
// after
curl -X POST http://host/upload -H "Content-Type: multipart/form-data; boundary=XYZ" -F file=@file.bin
Defensive patterns

Strategy: validation

Validate before calling

if (request.getHeader(HttpHeaderNames.CONTENT_TYPE) != null) {
  request.setExpectMultipart(true);
}

Try / catch

try { request.setExpectMultipart(true); } catch (IllegalStateException e) { /* no content-type: handle as plain body */ }

Prevention

When it happens

Trigger: Calling request.setExpectMultipart(true) on an incoming HTTP/1.x request whose headers do not include a Content-Type header (e.g. a POST with no Content-Type, or a request built manually by a test client).

Common situations: Clients (curl, custom HTTP clients, raw sockets) omitting Content-Type on form uploads; proxies stripping the header; unit tests constructing bare POST requests.

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/06530b127a67fef6. Report an issue: GitHub.