flowable/flowable-engine · error · FlowableIllegalArgumentException

historic case instanceIds are null

Error message

historic case instanceIds are null

What it means

BulkDeleteHistoricCaseInstancesCmd.execute throws FlowableIllegalArgumentException when the historic caseInstanceIds collection is null. The command records a bulk historic delete via the CmmnHistoryManager and needs a real collection to iterate; null input is rejected immediately.

Source

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

import org.flowable.cmmn.engine.impl.util.CommandContextUtil;
import org.flowable.common.engine.api.FlowableIllegalArgumentException;
import org.flowable.common.engine.impl.interceptor.Command;
import org.flowable.common.engine.impl.interceptor.CommandContext;

public class BulkDeleteHistoricCaseInstancesCmd implements Command<Object>, Serializable {

    private static final long serialVersionUID = 1L;

    protected Collection<String> caseInstanceIds;

    public BulkDeleteHistoricCaseInstancesCmd(Collection<String> caseInstanceIds) {
        this.caseInstanceIds = caseInstanceIds;
    }

    @Override
    public Object execute(CommandContext commandContext) {
        if (caseInstanceIds == null) {
            throw new FlowableIllegalArgumentException("historic case instanceIds are null");
        }

        if (caseInstanceIds.isEmpty()) {
            throw new FlowableIllegalArgumentException("historic case instanceIds are empty");
        }
        
        CommandContextUtil.getCmmnHistoryManager(commandContext).recordBulkDeleteHistoricCaseInstances(caseInstanceIds);
        
        return null;
    }

}

View on GitHub (pinned to d6d39ce1c6)

Solutions

  1. Pass a non-null collection of historic case instance ids
  2. Default null to an empty list at the call site
  3. Check the upstream id-query result and skip the bulk delete when nothing matched

Example fix

// before
historyService.bulkDeleteHistoricCaseInstances(historicIds);
// after
historyService.bulkDeleteHistoricCaseInstances(historicIds != null ? historicIds : Collections.emptyList());
Defensive patterns

Strategy: type-guard

Validate before calling

if (historicIds == null) historicIds = Collections.emptyList();

Type guard

boolean isNonNullCollection(Collection<?> c) { return c != null; }

Try / catch

try {
    historyService.bulkDeleteHistoricCaseInstances(ids);
} catch (FlowableIllegalArgumentException e) {
    log.error("Bulk historic delete rejected: {}", e.getMessage());
}

Prevention

When it happens

Trigger: Calling cmmnHistoryService.bulkDeleteHistoricCaseInstances(null) or constructing the command with a null id collection, typically from an unguarded upstream lookup returning null.

Common situations: History cleanup jobs passing a null batch of ids after an empty query; REST payloads omitting the ids array so it binds to null; copying code from BulkDeleteCaseInstancesCmd assumptions.

Related errors


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