flowable/flowable-engine · error · FlowableException

A request body was expected when executing a task action.

Error message

A request body was expected when executing a task action.

What it means

Thrown by executeTaskAction when POST /runtime/tasks/{taskId} is called without a JSON body. The TaskActionRequest (containing the 'action' field) is mandatory, so a null body makes the action indeterminable.

Solutions

  1. Send a body like {"action":"complete"} with Content-Type: application/json
  2. Use a supported action: complete, claim, delegate, resolve
  3. Ensure the HTTP client serializes and sends the request entity

Example fix

// before
curl -X POST .../runtime/tasks/123
// after
curl -X POST -H 'Content-Type: application/json' -d '{"action":"complete"}' .../runtime/tasks/123
Defensive patterns

Strategy: validation

Validate before calling

if (!body || !body.action) throw new Error('actionRequest with an action field is required');

Type guard

function isTaskActionRequest(b) { return b !== null && typeof b === 'object' && typeof b.action === 'string'; }

Try / catch

catch (e) { if (e.status === 400 && /request body was expected/.test(e.body && e.body.message)) { /* resend with {action: ...} */ } else throw e; }

Prevention

When it happens

Trigger: POST /runtime/tasks/{taskId} with empty body or without Content-Type: application/json; client forgets the {"action":"complete"} payload.

Common situations: Calling the action endpoint to 'ping' the task; curl POST without -d; HTTP client defaults dropping the body on POST.

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/e2d26fce9cae7605. Report an issue: GitHub.

Appendix: source

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

        // fields after it was saved so we can not use the in-memory task
        taskService.saveTask(task);
        task = taskService.createTaskQuery().taskId(task.getId()).singleResult();

        return restResponseFactory.createTaskResponse(task);
    }

    @ApiOperation(value = "Tasks actions", tags = {"Tasks"}, notes = "")
    @ApiResponses(value = {
            @ApiResponse(code = 200, message = "Indicates the action was executed."),
            @ApiResponse(code = 400, message = "When the body contains an invalid value or when the assignee is missing when the action requires it."),
            @ApiResponse(code = 404, message = "Indicates the requested task was not found."),
            @ApiResponse(code = 409, message = "Indicates the action cannot be performed due to a conflict. Either the task was updates simultaneously or the task was claimed by another user, in case of the claim action.")
    })
    @PostMapping(value = "/runtime/tasks/{taskId}")
    @ResponseStatus(value = HttpStatus.OK)
    public void executeTaskAction(@ApiParam(name = "taskId") @PathVariable String taskId, @RequestBody TaskActionRequest actionRequest) {
        if (actionRequest == null) {
            throw new FlowableException("A request body was expected when executing a task action.");
        }

        Task task = getTaskFromRequestWithoutAccessCheck(taskId);

        if (restApiInterceptor != null) {
            restApiInterceptor.executeTaskAction(task, actionRequest);
        }

        if (TaskActionRequest.ACTION_COMPLETE.equals(actionRequest.getAction())) {
            completeTask(task, actionRequest);

        } else if (TaskActionRequest.ACTION_CLAIM.equals(actionRequest.getAction())) {
            claimTask(task, actionRequest);

        } else if (TaskActionRequest.ACTION_UNCLAIM.equals(actionRequest.getAction())) {
            unclaimTask(task);

        } else if (TaskActionRequest.ACTION_DELEGATE.equals(actionRequest.getAction())) {

View on GitHub (pinned to d6d39ce1c6)