flowable/flowable-engine · error · FlowableIllegalArgumentException

task is null

Error message

task is null

What it means

SaveTaskCmd.execute throws FlowableIllegalArgumentException when the task passed to the command is null. The command persists changes to a TaskEntity, so a null task cannot be processed. This is the first validation in the command before any Flowable5 compatibility dispatching.

Source

Thrown at modules/flowable-engine/src/main/java/org/flowable/engine/impl/cmd/SaveTaskCmd.java:55

import org.flowable.task.service.impl.persistence.entity.TaskEntity;

/**
 * @author Joram Barrez
 */
public class SaveTaskCmd implements Command<Void>, Serializable {

    private static final long serialVersionUID = 1L;

    protected TaskEntity task;

    public SaveTaskCmd(Task task) {
        this.task = (TaskEntity) task;
    }

    @Override
    public Void execute(CommandContext commandContext) {
        if (task == null) {
            throw new FlowableIllegalArgumentException("task is null");
        }

        if (task.getProcessDefinitionId() != null && Flowable5Util.isFlowable5ProcessDefinitionId(commandContext, task.getProcessDefinitionId())) {
            Flowable5CompatibilityHandler compatibilityHandler = Flowable5Util.getFlowable5CompatibilityHandler();
            compatibilityHandler.saveTask(task);
            return null;
        }
        
        ProcessEngineConfigurationImpl processEngineConfiguration = CommandContextUtil.getProcessEngineConfiguration(commandContext);
        TaskService taskService = processEngineConfiguration.getTaskServiceConfiguration().getTaskService();

        if (task.getRevision() == 0) {
            TaskHelper.insertTask(task, null, true, false);

            FlowableEventDispatcher eventDispatcher = processEngineConfiguration.getEventDispatcher();
            if (eventDispatcher != null && eventDispatcher.isEnabled()) {
                processEngineConfiguration.getEventDispatcher().dispatchEvent(FlowableTaskEventBuilder.createEntityEvent(FlowableEngineEventType.TASK_CREATED, task),
                        processEngineConfiguration.getEngineCfgKey());

View on GitHub (pinned to d6d39ce1c6)

Solutions

  1. Pass a non-null Task (typically a TaskEntity obtained from a task query) to saveTask.
  2. Verify singleResult() / a task lookup returned a task before calling saveTask.
  3. Use taskService.newTask() to create a new task rather than passing null.

Example fix

// before
Task task = taskService.createTaskQuery().taskId(id).singleResult();
taskService.saveTask(task); // NPE/flowable error if not found
// after
Task task = taskService.createTaskQuery().taskId(id).singleResult();
if (task != null) {
    taskService.saveTask(task);
}
Defensive patterns

Strategy: validation

Validate before calling

Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
if (task == null) {
    throw new IllegalArgumentException("Task " + taskId + " not found");
}
taskService.saveTask(task);

Type guard

boolean isTaskPresent = task != null && task.getId() != null;

Prevention

When it happens

Trigger: Calling taskService.saveTask(null) or executing new SaveTaskCmd(null).

Common situations: taskService.createTaskQuery()...singleResult() returned null (task not found) and the null result was passed to saveTask; a task variable was reassigned/cleared before saving; API misuse in test code.

Related errors


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