flowable/flowable-engine · error · FlowableException
task does not have an endTime, cannot delete
Error message
task does not have an endTime, cannot delete
What it means
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.
Source
Thrown at modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/cmd/DeleteHistoricTaskInstanceCmd.java:54
public DeleteHistoricTaskInstanceCmd(String taskId) {
this.taskId = taskId;
}
@Override
public Object execute(CommandContext commandContext) {
if (taskId == null) {
throw new FlowableIllegalArgumentException("taskId is null");
}
// Check if task is completed
HistoricTaskInstanceEntity historicTaskInstance = CommandContextUtil.getHistoricTaskService().getHistoricTask(taskId);
if (historicTaskInstance == null) {
throw new FlowableObjectNotFoundException("No historic task instance found with id: " + taskId, HistoricTaskInstance.class);
}
if (historicTaskInstance.getEndTime() == null) {
throw new FlowableException("task does not have an endTime, cannot delete " + historicTaskInstance);
}
CommandContextUtil.getCmmnHistoryManager(commandContext).recordHistoricTaskDeleted(historicTaskInstance);
return null;
}
}
View on GitHub (pinned to d6d39ce1c6)
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.
Example fix
// before
historyService.deleteHistoricTaskInstance(taskId);
// after
HistoricTaskInstance hti = historyService.createHistoricTaskInstanceQuery().taskId(taskId).finished().singleResult();
if (hti != null) {
historyService.deleteHistoricTaskInstance(taskId);
} Defensive patterns
Strategy: validation
Validate before calling
HistoricTaskInstance hti = historyService.createHistoricTaskInstanceQuery().taskId(taskId).finished().singleResult(); if (hti != null) historyService.deleteHistoricTaskInstance(taskId);
Try / catch
try { historyService.deleteHistoricTaskInstance(taskId); } catch (FlowableException e) { log.warn("Task {} not finished; skipping history delete", taskId); } Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
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
- No historic task instance found with id:
- Historic case instance has not ended and can only be migrate
- Setting transient variable is not supported for read only de
- Setting localized name is not supported for read only delega
- Could not find an implementation of the org.flowable.cdi.imp
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/181877a71bcf815d.
Report an issue: GitHub.