flowable/flowable-engine · error · FlowableException

{task} is not suspended, so can't be activated

Error message

{task} is not suspended, so can't be activated

What it means

FlowableException thrown by ActivateTaskCmd.execute when the task exists and is not deleted but its suspended flag is false. Activation only makes sense on a suspended task; calling it on an already-active task is rejected.

Source

Thrown at modules/flowable-engine/src/main/java/org/flowable/engine/impl/cmd/ActivateTaskCmd.java:59

    public Void execute(CommandContext commandContext) {
        ProcessEngineConfigurationImpl processEngineConfiguration = CommandContextUtil.getProcessEngineConfiguration(commandContext);
        
        if (taskId == null) {
            throw new FlowableIllegalArgumentException("taskId is null");
        }

        TaskEntity task = processEngineConfiguration.getTaskServiceConfiguration().getTaskService().getTask(taskId);

        if (task == null) {
            throw new FlowableObjectNotFoundException("Cannot find task with id " + taskId, Task.class);
        }

        if (task.isDeleted()) {
            throw new FlowableException(task + " is already deleted");
        }

        if (!task.isSuspended()) {
            throw new FlowableException(task + " is not suspended, so can't be activated");
        }
        
        Clock clock = processEngineConfiguration.getClock();
        Date updateTime = clock.getCurrentTime();
        task.setSuspendedTime(null);
        task.setSuspendedBy(null);
        if (task.getInProgressStartTime() != null) {
            task.setState(Task.IN_PROGRESS);
        } else if (task.getClaimTime() != null) {
            task.setState(Task.CLAIMED);
        } else {
            task.setState(Task.CREATED);
        }
        task.setSuspensionState(SuspensionState.ACTIVE.getStateCode());
        
        HistoricTaskService historicTaskService = processEngineConfiguration.getTaskServiceConfiguration().getHistoricTaskService();
        historicTaskService.recordTaskInfoChange(task, updateTime, processEngineConfiguration);

View on GitHub (pinned to d6d39ce1c6)

Solutions

  1. Check task.isSuspended() via taskService.createTaskQuery().taskId(id).singleResult() before activating.
  2. Make the operation idempotent: skip activation when the task is already active.
  3. Avoid stacking suspension at multiple levels; suspend/activate at the process-instance level only when possible.
  4. Catch this FlowableException and treat it as a no-op in idempotent workflows.

Example fix

// before
taskService.activateTask(taskId);
// after
Task t = taskService.createTaskQuery().taskId(taskId).singleResult();
if (t != null && t.isSuspended()) {
    taskService.activateTask(taskId);
}
Defensive patterns

Strategy: validation

Validate before calling

Task t = taskService.createTaskQuery().taskId(taskId).singleResult();
if (t != null && t.isSuspended()) {
    taskService.activateTask(taskId);
}

Prevention

When it happens

Trigger: Calling taskService.activateTask(id) twice, or calling it on a task that was never suspended (e.g. activateProcessInstanceById already re-activated it).

Common situations: Idempotency bugs in retry loops; overlapping suspension of process instance, process definition, and task activating each other; concurrent admin scripts.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


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