{"record":{"id":"a49330a317fb57ff","repo":"flowable/flowable-engine","slug":"multipart-request-is-required-a49330","errorCode":null,"errorMessage":"Multipart request is required","messagePattern":"Multipart request is required","errorType":"validation","errorClass":"FlowableIllegalArgumentException","httpStatus":400,"severity":"error","filePath":"modules/flowable-dmn-rest/src/main/java/org/flowable/dmn/rest/service/api/repository/DmnDeploymentCollectionResource.java","lineNumber":159,"sourceCode":"\n    @ApiOperation(value = \"Create a new decision deployment\", nickname = \"uploadDecisionDeployment\", tags = {\n            \"Deployment\" }, 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. If multiple resources need to be deployed in a single deployment, compress the resources in a zip and make sure the file-name ends with .bar or .zip.\\n\"\n                    + \"\\n\"\n                    + \"An additional parameter (form-field) can be passed in the request body with name tenantId. The value of this field will be used as the id of the tenant this deployment is done in.\",\n            code = 201)\n    @ApiResponses(value = {\n            @ApiResponse(code = 201, message = \"Indicates the 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 deployment. The status-description contains additional information.\")\n    })\n    @ApiImplicitParams({\n        @ApiImplicitParam(name=\"file\", paramType = \"form\", dataType = \"java.io.File\")\n    })\n    @PostMapping(value = \"/dmn-repository/deployments\", produces = \"application/json\", consumes = \"multipart/form-data\")\n    @ResponseStatus(HttpStatus.CREATED)\n    public DmnDeploymentResponse uploadDeployment(@ApiParam(name = \"tenantId\") @RequestParam(value = \"tenantId\", required = false) String tenantId, HttpServletRequest request) {\n\n        if (!(request instanceof MultipartHttpServletRequest)) {\n            throw new FlowableIllegalArgumentException(\"Multipart request is required\");\n        }\n        \n        if (restApiInterceptor != null) {\n            restApiInterceptor.executeNewDeploymentForTenantId(tenantId);\n        }\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            DmnDeploymentBuilder deploymentBuilder = dmnRepositoryService.createDeployment();\n            String fileName = file.getOriginalFilename();\n            if (StringUtils.isEmpty(fileName) || !DmnResourceUtil.isDmnResource(fileName)) {","sourceCodeStart":141,"sourceCodeEnd":177,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable-dmn-rest/src/main/java/org/flowable/dmn/rest/service/api/repository/DmnDeploymentCollectionResource.java#L141-L177","documentation":"POST /dmn-repository/deployments only accepts multipart/form-data. The handler checks whether the incoming HttpServletRequest is a Spring MultipartHttpServletRequest and throws FlowableIllegalArgumentException if not. This is a request-shape validation: the deployment API always requires uploaded file parts.","triggerScenarios":"Sending POST /dmn-repository/deployments with Content-Type application/json, application/x-www-form-urlencoded, or missing multipart parts, so Spring never wraps the request as multipart.","commonSituations":"REST clients forgetting to set 'Content-Type: multipart/form-data' (or the boundary), curl calls using -d instead of -F, proxies/gateways stripping the multipart wrapper, or the servlet multipart support not being enabled in Spring Boot config.","solutions":["Send the request as multipart/form-data with the .dmn file as a file part (curl -F 'file=@decision.dmn').","Ensure the client library attaches files as form-data parts, not as a JSON body.","Verify multipart support is enabled (spring.servlet.multipart.enabled=true in Spring Boot).","Confirm no intermediary proxy rewrites the Content-Type or body."],"exampleFix":"// before\ncurl -X POST -H 'Content-Type: application/json' -d '{\"file\":\"decision.dmn\"}' http://host/flowable-dmn/dmn-repository/deployments\n// after\ncurl -X POST -F 'file=@decision.dmn' http://host/flowable-dmn/dmn-repository/deployments","handlingStrategy":"validation","validationCode":"const ct = request.headers['content-type'] || '';\nif (!ct.includes('multipart/form-data')) throw new Error('must send multipart/form-data');","typeGuard":null,"tryCatchPattern":"try { return await deploy(file); }\ncatch (e) { if (e.status === 400 && /Multipart request/.test(e.message)) { console.error('send multipart/form-data with a file part'); } throw e; }","preventionTips":["Use curl -F or a client that sends file parts for deployment uploads","Never send JSON bodies to the deployments endpoint","Enable servlet multipart support in Spring Boot","Check Content-Type includes a boundary"],"tags":["rest-api","http","multipart","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"}