flowable/flowable-engine · error · FlowableException

Case instance is still running, cannot delete

Error message

Case instance is still running, cannot delete 

What it means

DeleteHistoricCaseInstanceCmd refuses to delete a historic case instance whose endTime is null, because that means the case is still running (only the historic mirror exists). Deleting running-case history would corrupt state, so a FlowableException is thrown with the instance appended to the message.

Source

Thrown at modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/cmd/DeleteHistoricCaseInstanceCmd.java:59

    @Override
    public Object execute(CommandContext commandContext) {
        if (caseInstanceId == null) {
            throw new FlowableIllegalArgumentException("caseInstanceId is null");
        }
        // Check if case instance is still running
        CmmnEngineConfiguration cmmnEngineConfiguration = CommandContextUtil.getCmmnEngineConfiguration(commandContext);
        HistoricCaseInstanceEntity instance = cmmnEngineConfiguration.getHistoricCaseInstanceEntityManager().findById(caseInstanceId);

        if (instance == null) {
            throw new FlowableObjectNotFoundException("No historic case instance found with id: " + caseInstanceId, HistoricCaseInstance.class);
        }
        if (instance.isDeleted()) {
            return null;
        }


        if (instance.getEndTime() == null) {
            throw new FlowableException("Case instance is still running, cannot delete " + instance);
        }

        cmmnEngineConfiguration.getCmmnHistoryManager().recordHistoricCaseInstanceDeleted(caseInstanceId, instance.getTenantId());

        return null;
    }

}

View on GitHub (pinned to d6d39ce1c6)

Solutions

  1. Terminate/complete the case first, or delete the running case instance via the runtime API, then delete history
  2. Only target historic cases with a non-null endTime, e.g. query historicCaseInstanceQuery().finished()
  3. Skip still-running instances in batch cleanup scripts instead of failing the whole run

Example fix

// before
historyService.deleteHistoricCaseInstance(caseId);
// after
HistoricCaseInstance hci = historyService.createHistoricCaseInstanceQuery().caseInstanceId(caseId).singleResult();
if (hci != null && hci.getEndTime() != null) {
    historyService.deleteHistoricCaseInstance(caseId);
}
Defensive patterns

Strategy: validation

Validate before calling

HistoricCaseInstance hci = historyService.createHistoricCaseInstanceQuery().caseInstanceId(id).singleResult();
if (hci != null && hci.getEndTime() == null) { throw new IllegalStateException("case still running: " + id); }

Type guard

boolean isFinished(HistoricCaseInstance hci) { return hci != null && hci.getEndTime() != null; }

Try / catch

try { historyService.deleteHistoricCaseInstance(id); }
catch (FlowableException e) { if (e.getMessage() != null && e.getMessage().startsWith("Case instance is still running")) { /* defer until case ends */ } else throw e; }

Prevention

When it happens

Trigger: Calling deleteHistoricCaseInstance(id) for a case instance that has not yet completed/terminated (no end time recorded).

Common situations: Cleanup scripts deleting history without filtering on finished cases; deleting history for an active case by mistake; assuming 'historic record exists' implies 'case is finished'.

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/226f1d4a1f53b59f. Report an issue: GitHub.