{"record":{"id":"055946308b9c9b99","repo":"flowable/flowable-engine","slug":"multipart-request-is-required","errorCode":null,"errorMessage":"Multipart request is required","messagePattern":"Multipart request is required","errorType":"validation","errorClass":"FlowableIllegalArgumentException","httpStatus":400,"severity":"error","filePath":"modules/flowable-app-engine-rest/src/main/java/org/flowable/app/rest/service/api/repository/AppDeploymentCollectionResource.java","lineNumber":156,"sourceCode":"            \"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.\",\n            code = 201)\n    @ApiResponses(value = {\n            @ApiResponse(code = 201, message = \"Indicates the app deployment was created.\"),\n            @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.\")\n    })\n    @ApiImplicitParams({\n        @ApiImplicitParam(name=\"file\", paramType = \"form\", dataType = \"java.io.File\")\n    })\n    @PostMapping(value = \"/app-repository/deployments\", produces = \"application/json\", consumes = \"multipart/form-data\")\n    @ResponseStatus(HttpStatus.CREATED)\n    public AppDeploymentResponse uploadDeployment(@ApiParam(name = \"tenantId\") @RequestParam(value = \"tenantId\", required = false) String tenantId, HttpServletRequest request) {\n\n        if (restApiInterceptor != null) {\n            restApiInterceptor.executeNewDeploymentForTenantId(tenantId);\n        }\n        \n        if (!(request instanceof MultipartHttpServletRequest)) {\n            throw new FlowableIllegalArgumentException(\"Multipart request is required\");\n        }\n        \n        String queryString = request.getQueryString();\n        Map<String, String> decodedQueryStrings = splitQueryString(queryString);\n\n        MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;\n\n        if (multipartRequest.getFileMap().size() == 0) {\n            throw new FlowableIllegalArgumentException(\"Multipart request with file content is required\");\n        }\n\n        MultipartFile file = multipartRequest.getFileMap().values().iterator().next();\n\n        try {\n            AppDeploymentBuilder deploymentBuilder = appRepositoryService.createDeployment();\n            String fileName = file.getOriginalFilename();\n            if (StringUtils.isEmpty(fileName) || !(fileName.endsWith(\".app\") || fileName.toLowerCase().endsWith(\".bar\") || fileName.toLowerCase().endsWith(\".zip\"))) {\n                fileName = file.getName();","sourceCodeStart":138,"sourceCodeEnd":174,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable-app-engine-rest/src/main/java/org/flowable/app/rest/service/api/repository/AppDeploymentCollectionResource.java#L138-L174","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\ncurl -X POST -H 'Content-Type: application/octet-stream' --data-binary @my.app ...\n// after\ncurl -X POST -F 'file=@my.app' 'http://host/flowable-rest/app-repository/deployments?deploymentName=my-deploy'","handlingStrategy":"validation","validationCode":"# Ensure the request is multipart before sending\ndef upload_app(url, file_path):\n    with open(file_path, 'rb') as f:\n        files = {'file': (file_path, f, 'application/octet-stream')}\n        return requests.post(url, files=files)  # requests sets multipart/form-data","typeGuard":"// Server-side guard mirrors the library check\nif (!(request instanceof MultipartHttpServletRequest)) {\n    throw new FlowableIllegalArgumentException(\"Multipart request is required\");\n}","tryCatchPattern":"try {\n    ResponseEntity<String> resp = restTemplate.postForEntity(url, multipartEntity, String.class);\n} catch (HttpClientErrorException.BadRequest e) {\n    if (e.getResponseBodyAsString().contains(\"Multipart request is required\")) {\n        // resend as multipart/form-data with a file part\n    }\n}","preventionTips":["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."],"tags":["rest","multipart","http","validation"],"backgroundTag":"invalid-argument-value","analyzedSha":"d6d39ce1c69ff244f2d9dc6af756a9b95e865586","analyzedAt":"2026-09-11T06:41:19.413Z","contentChangedAt":"2026-09-11T06:41:19.413Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}