quarkusio/quarkus · error · IllegalArgumentException

Multipart form upload expects an entity of type MultipartFor

Error message

Multipart form upload expects an entity of type MultipartForm or List<EntityPart>, got: " + entityObj

What it means

Before sending a multipart request, setMultipartHeadersAndPrepareBody expects the request entity to be either a QuarkusMultipartForm/MultipartForm or a List<EntityPart>. Any other entity object cannot be converted into a multipart body, so the handler throws IllegalArgumentException including the entity's actual value.

Source

Thrown at independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/handlers/ClientSendRequestHandler.java:605

    }

    @SuppressWarnings("unchecked")
    private QuarkusMultipartFormUpload setMultipartHeadersAndPrepareBody(HttpClientRequest httpClientRequest,
            RestClientRequestContext state) throws Exception {
        QuarkusMultipartForm multipartForm;
        Object entityObj = state.getEntity().getEntity();
        boolean entityPartList = false;
        if (entityObj instanceof GenericEntity<?> ge) {
            entityPartList = EntityPartImpl.isEntityPartList(ge.getType());
            entityObj = ge.getEntity();
        }
        if (entityObj instanceof QuarkusMultipartForm) {
            multipartForm = (QuarkusMultipartForm) entityObj;
        } else if (entityObj instanceof List<?> list
                && (entityPartList || (!list.isEmpty() && list.get(0) instanceof EntityPart))) {
            multipartForm = entityPartsToMultipartForm((List<EntityPart>) list);
        } else {
            throw new IllegalArgumentException(
                    "Multipart form upload expects an entity of type MultipartForm or List<EntityPart>, got: " + entityObj);
        }

        MultivaluedMap<String, String> headerMap = state.getRequestHeadersAsMap();
        updateRequestHeadersFromConfig(state, headerMap);
        multipartForm.preparePojos(state);

        Object property = state.getConfiguration().getProperty(QuarkusRestClientProperties.MULTIPART_ENCODER_MODE);
        PausableHttpPostRequestEncoder.EncoderMode mode = PausableHttpPostRequestEncoder.EncoderMode.RFC1738;
        if (property != null) {
            mode = (PausableHttpPostRequestEncoder.EncoderMode) property;
        }
        QuarkusMultipartFormUpload multipartFormUpload = new QuarkusMultipartFormUpload(Vertx.currentContext(), multipartForm,
                true, maxChunkSize, mode);
        httpClientRequest.setChunked(multipartFormUpload.isChunked());
        setEntityRelatedHeaders(headerMap, state.getEntity());

        // multipart has its own headers:

View on GitHub (pinned to e1c734241f)

Solutions

  1. Pass a MultipartForm (e.g. MultipartForm.create().binaryFileUpload(...)) as the request entity.
  2. Or pass a List<EntityPart> built with EntityPart builder APIs.
  3. For proxied clients, declare the parameter with @MultipartForm so the client constructs the correct body type.
  4. Remove manual entity assignment that overrides the multipart body for multipart endpoints.

Example fix

// before
client.post(Map.of("file", data), FormData.class);
// after
MultipartForm form = MultipartForm.create()
    .binaryFileUpload("file", "data.bin", path, "application/octet-stream");
client.post(form, Response.class);
Defensive patterns

Strategy: type-guard

Validate before calling

if (!(entity instanceof MultipartForm) && !(entity instanceof List<?> l && (l.isEmpty() || l.get(0) instanceof EntityPart))) {
  throw new IllegalArgumentException("Multipart entity must be MultipartForm or List<EntityPart>");
}

Type guard

static boolean isValidMultipartEntity(Object e) {
  return e instanceof MultipartForm
      || (e instanceof List<?> l && !l.isEmpty() && l.stream().allMatch(EntityPart.class::isInstance));
}

Prevention

When it happens

Trigger: Calling a client method declared with multipart form output but passing a mismatched entity: a raw POJO, a Map, a non-EntityPart List, or setting the entity manually via Invocation/REST-assured-style builders instead of using @MultipartForm-typed parameters or MultipartForm.

Common situations: Manually building requests with a POJO body while the endpoint expects multipart/form-data; generic client code reusing a JSON-entity call path for a multipart endpoint; List<T> where T is not EntityPart and the list is non-empty with entityPartList flag unset.

Related errors


AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05). Data as JSON: /api/errors/31984c15b474d9a3. Report an issue: GitHub.