flowable/flowable-engine · error · FlowableException

A request body was expected when bulk updating tasks.

Error message

A request body was expected when bulk updating tasks.

What it means

Flowable's REST PUT /runtime/tasks (bulkUpdateTasks) throws FlowableException when the request body is missing entirely. The BulkTasksRequest parameter cannot be bound without a body, and the endpoint requires task ids plus the updates to apply.

Solutions

  1. Send a JSON body such as {"tasks":[...], "action":...} with PUT /runtime/tasks.
  2. Set the Content-Type: application/json header on the request.
  3. In curl, pass the payload with -d '{...}' (and -H "Content-Type: application/json").
  4. Check client code that the bulk-update call actually attaches the request object, not null.

Example fix

// before
curl -X PUT http://host/flowable-rest/runtime/tasks
// after
curl -X PUT -H "Content-Type: application/json" -d '{"tasks":[{"id":"1"}],"action":"complete"}' http://host/flowable-rest/runtime/tasks
Defensive patterns

Strategy: validation

Validate before calling

if (!body || Object.keys(body).length === 0) {
    throw new Error('Bulk update requires a JSON request body');
}

Type guard

function hasBulkBody(b) { return b != null && typeof b === 'object'; }

Try / catch

try {
    // PUT /runtime/tasks
} catch (e) {
    if (String(e.message).includes('A request body was expected when bulk updating tasks')) {
        // attach JSON body and retry once
    } else throw e;
}

Prevention

When it happens

Trigger: Sending PUT /runtime/tasks with no body, empty body, or wrong/missing Content-Type so Spring does not populate @RequestBody BulkTasksRequest.

Common situations: REST clients omitting Content-Type: application/json, sending GET-style requests with no payload, proxies stripping the body, or hand-crafted curl commands missing -d/--data.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11). Data as JSON: /api/errors/da94521ea6721559. Report an issue: GitHub.

Appendix: source

Thrown at modules/flowable-rest/src/main/java/org/flowable/rest/service/api/runtime/task/TaskCollectionResource.java:415

        if (restApiInterceptor != null) {
            restApiInterceptor.createTask(task, taskRequest);
        }
        
        taskService.saveTask(task);

        return restResponseFactory.createTaskResponse(task);
    }

    @ApiOperation(value = "Update Tasks", tags = { "Tasks" })
    @ApiResponses(value = {
            @ApiResponse(code = 201, message = "Indicates request was successful and the tasks are returned"),
            @ApiResponse(code = 400, message = "Indicates a parameter was passed in the wrong format or that delegationState has an invalid value (other than pending and resolved). The status-message contains additional information.")
    })
    @PutMapping(value = "/runtime/tasks", produces = "application/json")
    public DataResponse<TaskResponse> bulkUpdateTasks(@RequestBody BulkTasksRequest bulkTasksRequest) {

        if (bulkTasksRequest == null) {
            throw new FlowableException("A request body was expected when bulk updating tasks.");
        }
        if (bulkTasksRequest.getTaskIds() == null) {
            throw new FlowableIllegalArgumentException("taskIds can not be null for bulk update tasks requests");
        }

        Collection<Task> taskList = getTasksFromIdList(bulkTasksRequest.getTaskIds());

        if (taskList.size() != bulkTasksRequest.getTaskIds().size()) {
            taskList.stream().forEach(task -> bulkTasksRequest.getTaskIds().remove(task.getId()));
            throw new FlowableObjectNotFoundException(
                    "Could not find task instance with id:" + bulkTasksRequest.getTaskIds().stream().collect(Collectors.joining(",")));
        }

        // Populate the task properties based on the request
        populateTasksFromRequest(taskList, bulkTasksRequest);

        if (restApiInterceptor != null) {
            restApiInterceptor.bulkUpdateTasks(taskList, bulkTasksRequest);

View on GitHub (pinned to d6d39ce1c6)