flowable/flowable-engine · error · FlowableIllegalArgumentException
Multipart request is required
Error message
Multipart request is required
What it means
Thrown by AppDeploymentCollectionResource.uploadDeployment when the HTTP request handling the app deployment upload is not a MultipartHttpServletRequest. Flowable requires multipart/form-data because it reads the uploaded .app/.zip file from the multipart file map. A plain POST body (raw bytes, JSON, or a missing/incorrect Content-Type) triggers this.
Source
Thrown at modules/flowable-app-engine-rest/src/main/java/org/flowable/app/rest/service/api/repository/AppDeploymentCollectionResource.java:156
"App Deployments" }, consumes = "multipart/form-data", produces = "application/json", notes = "The request body should contain data of type multipart/form-data. There should be exactly one file in the request, any additional files will be ignored. The deployment name is the name of the file-field passed in. Make sure the file-name ends with .app, .zip or .bar.",
code = 201)
@ApiResponses(value = {
@ApiResponse(code = 201, message = "Indicates the app deployment was created."),
@ApiResponse(code = 400, message = "Indicates there was no content present in the request body or the content mime-type is not supported for app deployment. The status-description contains additional information.")
})
@ApiImplicitParams({
@ApiImplicitParam(name="file", paramType = "form", dataType = "java.io.File")
})
@PostMapping(value = "/app-repository/deployments", produces = "application/json", consumes = "multipart/form-data")
@ResponseStatus(HttpStatus.CREATED)
public AppDeploymentResponse uploadDeployment(@ApiParam(name = "tenantId") @RequestParam(value = "tenantId", required = false) String tenantId, HttpServletRequest request) {
if (restApiInterceptor != null) {
restApiInterceptor.executeNewDeploymentForTenantId(tenantId);
}
if (!(request instanceof MultipartHttpServletRequest)) {
throw new FlowableIllegalArgumentException("Multipart request is required");
}
String queryString = request.getQueryString();
Map<String, String> decodedQueryStrings = splitQueryString(queryString);
MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
if (multipartRequest.getFileMap().size() == 0) {
throw new FlowableIllegalArgumentException("Multipart request with file content is required");
}
MultipartFile file = multipartRequest.getFileMap().values().iterator().next();
try {
AppDeploymentBuilder deploymentBuilder = appRepositoryService.createDeployment();
String fileName = file.getOriginalFilename();
if (StringUtils.isEmpty(fileName) || !(fileName.endsWith(".app") || fileName.toLowerCase().endsWith(".bar") || fileName.toLowerCase().endsWith(".zip"))) {
fileName = file.getName();View on GitHub (pinned to d6d39ce1c6)
Solutions
- Send the file as multipart/form-data, e.g. curl -F "file=@my.app" ".../app-repository/deployments?deploymentName=MyDeploy".
- Verify Content-Type: multipart/form-data with boundary is set (do not set it manually for FormData in browsers — let the client set the boundary).
- Ensure Spring's MultipartResolver is enabled so the request is wrapped as MultipartHttpServletRequest.
- Check proxies/gateways preserve multipart bodies and headers.
Example fix
// before curl -X POST -H 'Content-Type: application/octet-stream' --data-binary @my.app ... // after curl -X POST -F 'file=@my.app' 'http://host/flowable-rest/app-repository/deployments?deploymentName=my-deploy'
Defensive patterns
Strategy: validation
Validate before calling
# Ensure the request is multipart before sending
def upload_app(url, file_path):
with open(file_path, 'rb') as f:
files = {'file': (file_path, f, 'application/octet-stream')}
return requests.post(url, files=files) # requests sets multipart/form-data Type guard
// Server-side guard mirrors the library check
if (!(request instanceof MultipartHttpServletRequest)) {
throw new FlowableIllegalArgumentException("Multipart request is required");
} Try / catch
try {
ResponseEntity<String> resp = restTemplate.postForEntity(url, multipartEntity, String.class);
} catch (HttpClientErrorException.BadRequest e) {
if (e.getResponseBodyAsString().contains("Multipart request is required")) {
// resend as multipart/form-data with a file part
}
} Prevention
- Use -F in curl, not --data-binary, for uploads.
- Let HTTP clients set the multipart Content-Type (with boundary).
- Ensure Spring's multipart support is enabled server-side.
- Verify gateways preserve Content-Type and multipart bodies.
When it happens
Trigger: POST /app-repository/deployments (optionally /{tenantId}) without multipart/form-data Content-Type, without a file part, or through a client/proxy that does not forward multipart correctly.
Common situations: curl -d instead of curl -F; fetch/axios sending FormData without proper content type; Spring MultipartResolver not configured so the wrapper is absent; gateways that strip or rewrite Content-Type.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- Multipart request with file content is required
- No file content was found in request body.
- A request body was expected when bulk updating tasks.
- taskIds can not be null for bulk update tasks requests
- Multipart request is required
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/055946308b9c9b99.
Report an issue: GitHub.