{"record":{"id":"fbb1b6ec1f46ef01","repo":"flowable/flowable-engine","slug":"multipart-request-with-file-content-is-required","errorCode":null,"errorMessage":"Multipart request with file content is required","messagePattern":"Multipart request with file content 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":165,"sourceCode":"    @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();\n            }\n\n            if (fileName.endsWith(\".app\")) {\n                try (final InputStream fileInputStream = file.getInputStream()) {\n                    deploymentBuilder.addInputStream(fileName, fileInputStream);\n                }\n\n            } else if (fileName.toLowerCase().endsWith(\".bar\") || fileName.toLowerCase().endsWith(\".zip\")) {\n                try (InputStream fileInputStream = file.getInputStream();","sourceCodeStart":147,"sourceCodeEnd":183,"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#L147-L183","documentation":"Thrown by AppDeploymentCollectionResource.uploadDeployment when the request is multipart but contains no file entries (multipartRequest.getFileMap().size() == 0). Flowable needs at least one file part to build the deployment. It signals a structurally valid multipart request with missing file content.","triggerScenarios":"POST /app-repository/deployments with multipart/form-data but only text/field parts, or an empty file part not registered in the file map.","commonSituations":"Client sends form fields (deploymentName etc.) but forgets the file input; wrong part name/type so Spring does not classify it as a file; browser form without enctype='multipart/form-data'; empty FormData append.","solutions":["Attach at least one file part, e.g. FormData.append('file', fileObject) in JS or curl -F 'file=@my.app'.","Use a proper file input (<input type='file'>) so the part is a file, not a text field.","Verify the part is non-empty and has a filename.","Log multipartRequest.getFileMap() server-side to confirm which parts Spring sees."],"exampleFix":"// before\nconst fd = new FormData(); fd.append('deploymentName', 'x'); // no file part\n// after\nconst fd = new FormData();\nfd.append('file', appFileInput.files[0]);\nfd.append('deploymentName', 'x');","handlingStrategy":"validation","validationCode":"// client-side: ensure a file part is appended\nif (!fileInput.files || fileInput.files.length === 0) {\n  throw new Error('Select an .app or .zip file before uploading');\n}\nconst fd = new FormData();\nfd.append('file', fileInput.files[0]);","typeGuard":null,"tryCatchPattern":"try {\n    restTemplate.postForEntity(uploadUrl, requestEntity, String.class);\n} catch (HttpClientErrorException.BadRequest e) {\n    if (e.getResponseBodyAsString().contains(\"file content is required\")) {\n        // retry with an actual file part in the multipart body\n    }\n}","preventionTips":["Always append a file object (not a string field) as the file part.","Use <input type='file'> with a real File/Blob.","Never send an empty file part.","Test uploads with curl -F before wiring UI code."],"tags":["rest","multipart","validation","upload"],"backgroundTag":"empty-required-field","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"}