flowable/flowable-engine · error · FlowableException

Task ${taskId} is not suspended, so can't be activated

Error message

Task ${taskId} is not suspended, so can't be activated

What it means

Flowable CMMN throws this when ActivateTaskCmd is executed against a plan item / task whose entity is not currently suspended. Activation (clearing suspendedTime/suspendedBy) is only meaningful for suspended tasks, so the command fails fast with a FlowableException to prevent an invalid state transition.

Source

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

    public Void execute(CommandContext commandContext) {
        CmmnEngineConfiguration cmmnEngineConfiguration = CommandContextUtil.getCmmnEngineConfiguration(commandContext);
        
        if (taskId == null) {
            throw new FlowableIllegalArgumentException("taskId is null");
        }

        TaskEntity task = cmmnEngineConfiguration.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 " + taskId + " is already deleted");
        }

        if (!task.isSuspended()) {
            throw new FlowableException("Task " + taskId + " is not suspended, so can't be activated");
        }
        
        Clock clock = cmmnEngineConfiguration.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());
        
        List<PlanItemInstanceEntity> planItemInstances = cmmnEngineConfiguration.getPlanItemInstanceEntityManager().findByReferenceId(task.getId());
        
        if (planItemInstances != null && !planItemInstances.isEmpty()) {

View on GitHub (pinned to d6d39ce1c6)

Solutions

  1. Check task.isSuspended() (via TaskService.createTaskQuery().taskId(id).singleResult()) before calling activateTask
  2. Skip or log tasks already active instead of activating unconditionally
  3. Serialize activation calls (idempotent handling) so concurrent callers don't double-activate
  4. Verify the correct taskId was passed — a wrong/stale id may point at a never-suspended task

Example fix

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

Strategy: validation

Validate before calling

Task t = cmmnTaskService.createTaskQuery().taskId(taskId).singleResult();
if (t == null) throw new IllegalArgumentException("task not found: " + taskId);
boolean canActivate = t.isSuspended();

Type guard

boolean canActivate(Task t) { return t != null && t.isSuspended(); }

Try / catch

try {
    cmmnTaskService.activateTask(taskId);
} catch (FlowableException e) {
    if (e.getMessage().contains("not suspended")) { /* already active: skip/log */ }
    else throw e;
}

Prevention

When it happens

Trigger: Calling CmmnTaskService.activateTask(taskId) (or the ActivateTaskCmd directly) on a task whose TaskEntity.isSuspended() is false — e.g. the task was never suspended, or it was already activated in a prior call.

Common situations: Double-invocation of activation after a retry, activating tasks in bulk where only some are suspended, race between two threads/instances where one already activated the task, or confusing suspend with other state changes like completion.

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