flowable/flowable-engine · error · FlowableException

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

Error message

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

What it means

TaskHelper.deleteTask throws this when the task is still attached to a process execution (task.getExecutionId() != null). Standalone task deletion is only allowed for tasks that do not belong to a running process instance; such tasks' lifecycle is owned by the process.

Source

Thrown at modules/flowable-engine/src/main/java/org/flowable/engine/impl/util/TaskHelper.java:572

    }

    protected static void fireTaskDeletedEvent(TaskEntity task, CommandContext commandContext, FlowableEventDispatcher eventDispatcher) {
        if (eventDispatcher != null && eventDispatcher.isEnabled()) {
            ProcessEngineConfigurationImpl processEngineConfiguration = CommandContextUtil.getProcessEngineConfiguration(commandContext);
            CommandContextUtil.getEventDispatcher(commandContext).dispatchEvent(
                    FlowableEventBuilder.createEntityEvent(FlowableEngineEventType.ENTITY_DELETED, task),
                    processEngineConfiguration.getEngineCfgKey());
        }
    }

    public static void deleteTask(String taskId, String deleteReason, boolean cascade) {
        CommandContext commandContext = CommandContextUtil.getCommandContext();
        ProcessEngineConfigurationImpl processEngineConfiguration = CommandContextUtil.getProcessEngineConfiguration(commandContext);
        TaskEntity task = processEngineConfiguration.getTaskServiceConfiguration().getTaskService().getTask(taskId);

        if (task != null) {
            if (task.getExecutionId() != null) {
                throw new FlowableException("The " + task + " cannot be deleted because is part of a running process");
            } else if (task.getScopeId() != null && ScopeTypes.CMMN.equals(task.getScopeType())) {
                throw new FlowableException("The " + task + " cannot be deleted because is part of a running case");
            }

            if (Flowable5Util.isFlowable5ProcessDefinitionId(commandContext, task.getProcessDefinitionId())) {
                Flowable5CompatibilityHandler compatibilityHandler = Flowable5Util.getFlowable5CompatibilityHandler();
                compatibilityHandler.deleteTask(taskId, deleteReason, cascade);
                return;
            }

            deleteTask(task, deleteReason, cascade, true, true);

        } else if (cascade) {
            deleteHistoricTask(taskId);
        }
    }

    public static void deleteTasksByProcessInstanceId(String processInstanceId, String deleteReason, boolean cascade) {

View on GitHub (pinned to d6d39ce1c6)

Solutions

  1. Only delete standalone tasks: query with taskService.createTaskQuery().taskId(id).processInstanceIdUnspecified() or check task.getProcessInstanceId() == null first.
  2. To remove an in-process task, end it via taskService.completeTask or change the process (boundary event / process instance cancellation).
  3. Cancel the whole process instance via runtimeService.deleteProcessInstance(pid, reason) if the intent is cleanup.
  4. If cascade removal is needed, use deleteTask(taskId, true) only where legitimate; this error still blocks execution-bound tasks.

Example fix

// before
taskService.deleteTask(taskId, "cleanup");
// after
Task t = taskService.createTaskQuery().taskId(taskId).singleResult();
if (t != null && t.getProcessInstanceId() == null) {
    taskService.deleteTask(taskId, "cleanup");
} else {
    runtimeService.deleteProcessInstance(t.getProcessInstanceId(), "cleanup");
}
Defensive patterns

Strategy: validation

Validate before calling

Task t = taskService.createTaskQuery().taskId(taskId).singleResult();
boolean deletable = t != null && t.getExecutionId() == null && !ScopeTypes.CMMN.equals(t.getScopeType());

Type guard

boolean isStandaloneTask(Task t) { return t != null && t.getExecutionId() == null && t.getProcessInstanceId() == null; }

Try / catch

try { taskService.deleteTask(taskId, reason); } catch (FlowableException e) { log.warn("Task {} is process-bound: {}", taskId, e.getMessage()); }

Prevention

When it happens

Trigger: Calling TaskService.deleteTask(taskId) (or deleteTasks) with the id of a task that has an executionId, i.e. a user task inside a running BPMN process instance.

Common situations: Admin cleanup scripts iterating all tasks including in-process ones; deleting tasks fetched without filtering on processInstanceId being null; trying to remove a stale-looking user task that is actually part of an active workflow.

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