{"record":{"id":"733e8ce19e8bf80f","repo":"flowable/flowable-engine","slug":"task-is-already-deleted-733e8c","errorCode":null,"errorMessage":"task + \" is already deleted\"","messagePattern":"task \\+ \" is already deleted\"","errorType":"exception","errorClass":"FlowableException","httpStatus":null,"severity":"error","filePath":"modules/flowable-engine/src/main/java/org/flowable/engine/impl/cmd/NeedsActiveTaskCmd.java","lineNumber":57,"sourceCode":"        this.taskId = taskId;\n    }\n\n    @Override\n    public T execute(CommandContext commandContext) {\n\n        if (taskId == null) {\n            throw new FlowableIllegalArgumentException(\"taskId is null\");\n        }\n\n        ProcessEngineConfigurationImpl processEngineConfiguration = CommandContextUtil.getProcessEngineConfiguration(commandContext);\n        TaskEntity task = processEngineConfiguration.getTaskServiceConfiguration().getTaskService().getTask(taskId);\n\n        if (task == null) {\n            throw new FlowableObjectNotFoundException(\"Cannot find task with id \" + taskId, Task.class);\n        }\n\n        if (task.isDeleted()) {\n            throw new FlowableException(task + \" is already deleted\");\n        }\n\n        if (task.isSuspended()) {\n            throw new FlowableException(getSuspendedTaskExceptionPrefix() + \" a suspended \" + task);\n        }\n\n        return execute(commandContext, task);\n    }\n\n    /**\n     * Subclasses must implement in this method their normal command logic. The provided task is ensured to be active.\n     */\n    protected abstract T execute(CommandContext commandContext, TaskEntity task);\n\n    /**\n     * Subclasses can override this method to provide a customized exception message that will be thrown when the task is suspended.\n     */\n    protected String getSuspendedTaskExceptionPrefix() {","sourceCodeStart":39,"sourceCodeEnd":75,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable-engine/src/main/java/org/flowable/engine/impl/cmd/NeedsActiveTaskCmd.java#L39-L75","documentation":"Flowable throws this FlowableException when a NeedsActiveTaskCmd targets a task whose isDeleted flag is set. Deleted tasks remain momentarily visible before cleanup, and any claim/complete/resolve attempt on them is rejected.","triggerScenarios":"Calling TaskService.claim/complete/setAssignee on a task that was deleted (e.g. its execution ended or the task was removed) but whose row still carries the deleted flag.","commonSituations":"A parallel branch of the process cancelled (terminated) the task while a user was acting on it; race between task deletion (process end/termination) and user submission; cascading delete via process instance deletion while forms were open.","solutions":["Catch FlowableException and treat the deleted task as a cancelled work item — notify the user instead of retrying.","Re-query the task before submission to confirm it is still active: taskService.createTaskQuery().taskId(id).singleResult().","Avoid deleting process instances while users hold open task forms, or handle the resulting exception in the UI.","Wrap task mutations in OptimisticLocking/FlowableException handling that re-reads current task state."],"exampleFix":"// before\ntaskService.complete(taskId); // may throw: Task ... is already deleted\n// after\nTask task = taskService.createTaskQuery().taskId(taskId).singleResult();\nif (task != null && !task.isDeleted()) {\n    taskService.complete(taskId);\n} else {\n    // treat as cancelled work item\n}","handlingStrategy":"try-catch","validationCode":"Task task = taskService.createTaskQuery().taskId(taskId).singleResult();\nif (task == null || task.isDeleted()) { throw new IllegalStateException(\"Task no longer active\"); }","typeGuard":null,"tryCatchPattern":"try {\n    taskService.complete(taskId);\n} catch (FlowableException e) {\n    if (e.getMessage().endsWith(\"is already deleted\")) {\n        notifyUserTaskCancelled(taskId);\n    } else { throw e; }\n}","preventionTips":["Handle task cancellation events so open user forms are invalidated.","Avoid terminating process instances while users hold open task forms.","Re-read task state right before mutation.","Notify users when their task was cancelled by process termination."],"tags":["flowable","deleted-task","race-condition"],"backgroundTag":"invalid-state-transition","analyzedSha":"d6d39ce1c69ff244f2d9dc6af756a9b95e865586","analyzedAt":"2026-09-11T06:41:19.413Z","contentChangedAt":"2026-09-11T06:41:19.413Z","schemaVersion":2},"datasetVersion":"2026-09-18T11:17:12.947Z"}