flowable/flowable-engine · error · FlowableException
A request body was expected when updating the task.
Error message
A request body was expected when updating the task.
What it means
PUT /cmmn-runtime/tasks/{taskId} expects a TaskRequest body describing the fields to update. Flowable throws a plain FlowableException if the deserialized body is null, i.e. the request was sent without a body or with an empty body.
Solutions
- Send a JSON body with the task fields to update, e.g. {"name":"Reviewed","description":"..."}
- Set the Content-Type: application/json header on the PUT request
- Verify the HTTP client actually transmits the body (some clients omit it when no fields are set)
Example fix
// before
restTemplate.put("/cmmn-runtime/tasks/123", null);
// after
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
restTemplate.exchange("/cmmn-runtime/tasks/123", HttpMethod.PUT,
new HttpEntity<>(Collections.singletonMap("name", "Reviewed"), headers), TaskResponse.class); Defensive patterns
Strategy: validation
Validate before calling
function canUpdateTask(patch) {
return patch != null && typeof patch === 'object' && Object.keys(patch).length > 0;
} Type guard
function hasBody(b) {
return b != null && typeof b === 'object';
} Try / catch
try {
await put(`/cmmn-runtime/tasks/${taskId}`, patch);
} catch (e) {
if (e.status === 500 && /request body was expected/.test(e.body.message)) {
throw new Error('PUT task requires a JSON body');
}
throw e;
} Prevention
- Always set Content-Type: application/json on PUT requests
- Assert the payload is serialized before sending
- Avoid null bodies: send at least one updatable field
When it happens
Trigger: PUT to /cmmn-runtime/tasks/{taskId} with no request body, an empty body, or a Content-Type that prevents JSON deserialization into TaskRequest.
Common situations: Calling the endpoint with GET-style tooling that omits the body; forgetting to set Content-Type: application/json; proxies or clients stripping empty bodies; sending body as form data.
Related errors
- A request body was expected when bulk updating tasks.
- A request body was expected when executing a task action.
- A request body was expected when executing the form submit.
- Invalid body was supplied
- No action found in request body.
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/0365fa5e6d77d108.
Report an issue: GitHub.
Appendix: source
Thrown at modules/flowable-cmmn-rest/src/main/java/org/flowable/cmmn/rest/service/api/runtime/task/TaskResource.java:80
@ApiResponse(code = 404, message = "Indicates the requested task was not found.")
})
@GetMapping(value = "/cmmn-runtime/tasks/{taskId}", produces = "application/json")
public TaskResponse getTask(@ApiParam(name = "taskId") @PathVariable String taskId) {
return restResponseFactory.createTaskResponse(getTaskFromRequest(taskId));
}
@ApiOperation(value = "Update a task", tags = {
"Tasks" }, notes = "All request values are optional. For example, you can only include the assignee attribute in the request body JSON-object, only updating the assignee of the task, leaving all other fields unaffected. When an attribute is explicitly included and is set to null, the task-value will be updated to null. Example: {\"dueDate\" : null} will clear the duedate of the task).")
@ApiResponses(value = {
@ApiResponse(code = 200, message = "Indicates the task was updated."),
@ApiResponse(code = 404, message = "Indicates the requested task was not found."),
@ApiResponse(code = 409, message = "Indicates the requested task was updated simultaneously.")
})
@PutMapping(value = "/cmmn-runtime/tasks/{taskId}", produces = "application/json")
public TaskResponse updateTask(@ApiParam(name = "taskId") @PathVariable String taskId, @RequestBody TaskRequest taskRequest) {
if (taskRequest == null) {
throw new FlowableException("A request body was expected when updating the task.");
}
Task task = getTaskFromRequestWithoutAccessCheck(taskId);
// Populate the task properties based on the request
populateTaskFromRequest(task, taskRequest);
if (restApiInterceptor != null) {
restApiInterceptor.updateTask(task, taskRequest);
}
// Save the task and fetch again, it's possible that an
// assignment-listener has updated
// fields after it was saved so we can't use the in-memory task
taskService.saveTask(task);
task = taskService.createTaskQuery().taskId(task.getId()).singleResult();
return restResponseFactory.createTaskResponse(task);View on GitHub (pinned to d6d39ce1c6)