flowable/flowable-engine · error · FlowableException

The ${task} cannot be deleted because is part of a running c

Error message

The ${task} cannot be deleted because is part of a running case instance

What it means

TaskHelper.deleteTask(taskId, deleteReason, cascade, config) refuses to delete a standalone task that belongs to a running CMMN case instance (task.scopeId set and scopeType CMMN). Case tasks are managed by the case engine's lifecycle, so deleting them directly would corrupt case state; the caller must complete/terminate the plan item instead.

Source

Thrown at modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/task/TaskHelper.java:74

        }

        if (taskEntity.getAssignee() != null) {
            addAssigneeIdentityLinks(taskEntity, cmmnEngineConfiguration);
            fireAssignmentEvents(taskEntity, cmmnEngineConfiguration);
        }

    }
    
    public static void completeTask(TaskEntity task, String userId, CmmnEngineConfiguration cmmnEngineConfiguration) {
        cmmnEngineConfiguration.getPlanItemInstanceEntityManager().updateHumanTaskPlanItemInstanceCompletedBy(task, userId);
        internalDeleteTask(task, userId, null, false, true, cmmnEngineConfiguration);
    }

    public static void deleteTask(String taskId, String deleteReason, boolean cascade, CmmnEngineConfiguration cmmnEngineConfiguration) {
        TaskEntity task = cmmnEngineConfiguration.getTaskServiceConfiguration().getTaskService().getTask(taskId);
        if (task != null) {
            if (task.getScopeId() != null && ScopeTypes.CMMN.equals(task.getScopeType())) {
                throw new FlowableException("The " + task + " cannot be deleted because is part of a running case instance");
            } else if (task.getExecutionId() != null) {
                throw new FlowableException("The " + task + " cannot be deleted because is part of a running process instance");
            }
            deleteTask(task, deleteReason, cascade, true, cmmnEngineConfiguration);
            
        } else if (cascade) {
            deleteHistoricTask(taskId, cmmnEngineConfiguration);
        }
    }
    
    public static void deleteTask(TaskEntity task, String deleteReason, boolean cascade, 
            boolean fireEvents, CmmnEngineConfiguration cmmnEngineConfiguration) {
        
        internalDeleteTask(task, null, deleteReason, cascade, fireEvents, cmmnEngineConfiguration);
    }

    protected static void internalDeleteTask(TaskEntity task, String userId, String deleteReason, boolean cascade, 
            boolean fireEvents, CmmnEngineConfiguration cmmnEngineConfiguration) {

View on GitHub (pinned to d6d39ce1c6)

Solutions

  1. Delete or terminate the owning case/plan item instead (CaseInstanceService/deleteCaseInstance or complete the plan item), letting the engine remove the task
  2. Filter CMMN-scoped tasks out of bulk deletion logic: skip tasks where scopeId != null and scopeType == CMMN
  3. If the case is actually finished, clean up via history deletion (deleteHistoricTask) rather than the runtime task
  4. Use cascade=false only for standalone tasks; handle case tasks through the case runtime service

Example fix

// before
taskService.deleteTask(taskId, "cleanup");
// after
TaskEntity task = ...getTask(taskId);
if (task.getScopeId() != null && ScopeTypes.CMMN.equals(task.getScopeType())) {
    cmmnRuntimeService.deleteCaseInstance(task.getScopeId(), "cleanup");
} else {
    taskService.deleteTask(taskId, "cleanup");
}
Defensive patterns

Strategy: validation

Validate before calling

if (task.getScopeId() != null && ScopeTypes.CMMN.equals(task.getScopeType())) {
    throw new IllegalArgumentException("task " + task.getId() + " belongs to case " + task.getScopeId() + "; delete the case instead");
}

Type guard

boolean isStandalone(Task t) { return t.getScopeId() == null && t.getExecutionId() == null; }

Try / catch

try { taskService.deleteTask(taskId, reason); } catch (FlowableException e) { if (e.getMessage().contains("running case instance")) { cmmnRuntimeService.deleteCaseInstance(scopeId, reason); } else throw e; }

Prevention

When it happens

Trigger: Calling TaskService.deleteTask(taskId) (or TaskHelper.deleteTask) on a task whose getScopeId() != null and scopeType == ScopeTypes.CMMN, i.e. any task created by a human task plan item in an active case.

Common situations: Admin/cleanup jobs that purge stale tasks hitting CMMN-created tasks; custom task management UIs exposing delete on case tasks; migrating legacy cleanup scripts to a mixed process/case environment.

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