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
- Delete or terminate the owning case/plan item instead (CaseInstanceService/deleteCaseInstance or complete the plan item), letting the engine remove the task
- Filter CMMN-scoped tasks out of bulk deletion logic: skip tasks where scopeId != null and scopeType == CMMN
- If the case is actually finished, clean up via history deletion (deleteHistoricTask) rather than the runtime task
- 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
- Filter tasks by scopeId/scopeType before bulk deletes
- Use case/runtime services to remove case-owned tasks
- Audit admin delete endpoints to disallow scoped tasks
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
- is created by the process engine and should be completed vi
- Setting variable is not supported for read only delegate exe
- Can only trigger a plan item that is in the ACTIVE state
- No External Worker job found for id: ${externalJobId}
- ${workerId} does not hold a lock on the requested job
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/e0a799de1603d8ed.
Report an issue: GitHub.