flowable/flowable-engine · error · FlowableIllegalArgumentException

caseInstanceId is null

Error message

caseInstanceId is null

What it means

DeleteHistoricCaseInstanceCmd first validates that a caseInstanceId was supplied; a null value throws FlowableIllegalArgumentException("caseInstanceId is null"). The command exists to remove a historic case instance record, so an id is mandatory before any history lookup.

Source

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

import org.flowable.common.engine.impl.interceptor.CommandContext;

/**
 * @author Tijs Rademakers
 */
public class DeleteHistoricCaseInstanceCmd implements Command<Object>, Serializable {

    private static final long serialVersionUID = 1L;
    
    protected String caseInstanceId;

    public DeleteHistoricCaseInstanceCmd(String caseInstanceId) {
        this.caseInstanceId = caseInstanceId;
    }

    @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());

View on GitHub (pinned to d6d39ce1c6)

Solutions

  1. Null-check (and emptiness-check) caseInstanceId before invoking the history service
  2. Fix the upstream source returning null ids (query result handling, entity mapping)
  3. Skip records without an id instead of calling the delete API for them

Example fix

// before
historyService.deleteHistoricCaseInstance(caseInstance.getId());
// after
if (caseInstance != null && caseInstance.getId() != null) {
    historyService.deleteHistoricCaseInstance(caseInstance.getId());
}
Defensive patterns

Strategy: validation

Validate before calling

if (caseInstanceId == null || caseInstanceId.isEmpty()) { throw new IllegalArgumentException("caseInstanceId required"); }
historyService.deleteHistoricCaseInstance(caseInstanceId);

Type guard

boolean hasId(CaseInstance ci) { return ci != null && ci.getId() != null && !ci.getId().isEmpty(); }

Try / catch

try { historyService.deleteHistoricCaseInstance(caseId); }
catch (FlowableIllegalArgumentException e) { if ("caseInstanceId is null".equals(e.getMessage())) { log.warn("skipped delete: null id"); } else throw e; }

Prevention

When it happens

Trigger: Calling CmmnHistoryService.deleteHistoricCaseInstance(null), e.g. when the id was read from an optional field or a query result that was empty.

Common situations: Iterating results where some entities expose null ids; unboxing from an Optional/getter chain returning null; batch cleanup scripts with unfiltered input.

Related errors


AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11). Data as JSON: /api/errors/47a208c1f08d834c. Report an issue: GitHub.