{"record":{"id":"181877a71bcf815d","repo":"flowable/flowable-engine","slug":"task-does-not-have-an-endtime-cannot-delete","errorCode":null,"errorMessage":"task does not have an endTime, cannot delete ","messagePattern":"task does not have an endTime, cannot delete ","errorType":"exception","errorClass":"FlowableException","httpStatus":null,"severity":"error","filePath":"modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/cmd/DeleteHistoricTaskInstanceCmd.java","lineNumber":54,"sourceCode":"    public DeleteHistoricTaskInstanceCmd(String taskId) {\n        this.taskId = taskId;\n    }\n\n    @Override\n    public Object execute(CommandContext commandContext) {\n\n        if (taskId == null) {\n            throw new FlowableIllegalArgumentException(\"taskId is null\");\n        }\n\n        // Check if task is completed\n        HistoricTaskInstanceEntity historicTaskInstance = CommandContextUtil.getHistoricTaskService().getHistoricTask(taskId);\n\n        if (historicTaskInstance == null) {\n            throw new FlowableObjectNotFoundException(\"No historic task instance found with id: \" + taskId, HistoricTaskInstance.class);\n        }\n        if (historicTaskInstance.getEndTime() == null) {\n            throw new FlowableException(\"task does not have an endTime, cannot delete \" + historicTaskInstance);\n        }\n\n        CommandContextUtil.getCmmnHistoryManager(commandContext).recordHistoricTaskDeleted(historicTaskInstance);\n        \n        return null;\n    }\n\n}\n","sourceCodeStart":36,"sourceCodeEnd":63,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/cmd/DeleteHistoricTaskInstanceCmd.java#L36-L63","documentation":"DeleteHistoricTaskInstanceCmd throws this FlowableException when the historic task exists but getEndTime() is null, i.e. the task never completed. Only finished tasks may be deleted through this command, because deleting a live task's history row would corrupt runtime/history consistency.","triggerScenarios":"Calling CmmnHistoryService.deleteHistoricTaskInstance(taskId) for a task that was created but not yet finished (no endTime), e.g. deleting the history of an in-progress CMMN task.","commonSituations":"Cleanup scripts that filter historic tasks only by existence and not by finished state; API calls that pass a runtime task id where a completed-task id was expected.","solutions":["Only call deleteHistoricTaskInstance for tasks whose endTime is set (query .finished() or check getEndTime() first).","If the intent is to remove an active task, cancel/complete the plan item through the runtime service instead of deleting its history.","Filter cleanup queries with createHistoricTaskInstanceQuery().finished() so only deletable rows are processed."],"exampleFix":"// before\nhistoryService.deleteHistoricTaskInstance(taskId);\n// after\nHistoricTaskInstance hti = historyService.createHistoricTaskInstanceQuery().taskId(taskId).finished().singleResult();\nif (hti != null) {\n    historyService.deleteHistoricTaskInstance(taskId);\n}","handlingStrategy":"validation","validationCode":"HistoricTaskInstance hti = historyService.createHistoricTaskInstanceQuery().taskId(taskId).finished().singleResult();\nif (hti != null) historyService.deleteHistoricTaskInstance(taskId);","typeGuard":null,"tryCatchPattern":"try { historyService.deleteHistoricTaskInstance(taskId); } catch (FlowableException e) { log.warn(\"Task {} not finished; skipping history delete\", taskId); }","preventionTips":["Filter cleanup queries with .finished().","Never delete history for tasks that are still active in a case instance.","Complete or terminate the plan item before removing its history."],"tags":["cmmn","history","invalid-state","java"],"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-14T11:17:12.474Z"}