flowable/flowable-engine · error · FlowableException
A request body was expected when executing the form submit.
Error message
A request body was expected when executing the form submit.
What it means
submitForm is declared with @RequestBody, so Spring would normally reject empty bodies, but Flowable guards explicitly: if the deserialized SubmitFormRequest is null (e.g. body was empty/whitespace or Content-Type mismatch prevented binding), it throws FlowableException with this message. It protects downstream code from dereferencing a null request object.
Solutions
- Send a valid JSON body with Content-Type: application/json
- Ensure the body contains at least taskId or processDefinitionId plus form properties
- Catch FlowableException mapped to HTTP 400 and validate the client payload before sending
Example fix
// before
curl -X POST -H "Content-Type: application/json" http://localhost:8080/flowable-rest/form/form-data
// after
curl -X POST -H "Content-Type: application/json" \
-d '{"taskId":"125","formProperties":[{"id":"approved","value":"true"}]}' \
http://localhost:8080/flowable-rest/form/form-data Defensive patterns
Strategy: validation
Validate before calling
if (!body || typeof body !== 'object') throw new Error('submitForm requires a JSON body');
if (!body.taskId && !body.processDefinitionId) throw new Error('taskId or processDefinitionId required'); Type guard
function isSubmitFormRequest(v) { return v !== null && typeof v === 'object' && ('taskId' in v || 'processDefinitionId' in v); } Try / catch
try { await submitForm(payload); } catch (e) { if (e.status === 400) showPayloadError(e); else throw e; } Prevention
- Always set Content-Type: application/json on POSTs
- Serialize the payload explicitly; never send an empty body
- Test endpoints with the exact client HTTP stack, including proxies
When it happens
Trigger: POST /form/form-data with an empty body, a body that is literally 'null', or a request whose Content-Type is not application/json so no body is bound.
Common situations: HTTP clients omitting -d/--data in curl; wrong Content-Type header (text/plain or form-urlencoded); proxies stripping the body on POST.
Understand the failure class
Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.
Related errors
- Invalid body was supplied
- taskIds can not be null for bulk update tasks requests
- A request body was expected when bulk updating tasks.
- Attachment name is required.
- Error converting request body to RestVariable instance
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/18d6d4f0cb2287fc.
Report an issue: GitHub.
Appendix: source
Thrown at modules/flowable-rest/src/main/java/org/flowable/rest/service/api/form/FormDataResource.java:106
}
if (restApiInterceptor != null) {
restApiInterceptor.accessFormData(formData);
}
return restResponseFactory.createFormDataResponse(formData);
}
@ApiOperation(value = "Submit task form data", tags = { "Forms" })
@ApiResponses(value = {
@ApiResponse(code = 200, message = "Indicates request was successful and the form data was submitted"),
@ApiResponse(code = 204, message = "If TaskId has been provided, Indicates request was successful and the form data was submitted. Returns empty"),
@ApiResponse(code = 400, message = "Indicates an parameter was passed in the wrong format. The status-message contains additional information.") })
@PostMapping(value = "/form/form-data", produces = "application/json")
public ProcessInstanceResponse submitForm(@RequestBody SubmitFormRequest submitRequest, HttpServletResponse response) {
if (submitRequest == null) {
throw new FlowableException("A request body was expected when executing the form submit.");
}
if (submitRequest.getTaskId() == null && submitRequest.getProcessDefinitionId() == null) {
throw new FlowableIllegalArgumentException("The taskId or processDefinitionId property has to be provided");
}
if (restApiInterceptor != null) {
restApiInterceptor.submitFormData(submitRequest);
}
Map<String, String> propertyMap = new HashMap<>();
if (submitRequest.getProperties() != null) {
for (RestFormProperty formProperty : submitRequest.getProperties()) {
propertyMap.put(formProperty.getId(), formProperty.getValue());
}
}
if (submitRequest.getTaskId() != null) {View on GitHub (pinned to d6d39ce1c6)