flowable/flowable-engine · error · FlowableIllegalArgumentException

processInstanceIds is empty

Error message

processInstanceIds is empty

What it means

BulkDeleteHistoricProcessInstancesCmd.execute throws FlowableIllegalArgumentException when the process instance id collection is non-null but empty. An empty list would be a no-op delete, so the engine treats it as an invalid call instead of silently succeeding.

Source

Thrown at modules/flowable-engine/src/main/java/org/flowable/engine/impl/cmd/BulkDeleteHistoricProcessInstancesCmd.java:40

import org.flowable.engine.impl.util.CommandContextUtil;

public class BulkDeleteHistoricProcessInstancesCmd implements Command<Object>, Serializable {

    private static final long serialVersionUID = 1L;
    protected Collection<String> processInstanceIds;

    public BulkDeleteHistoricProcessInstancesCmd(Collection<String> processInstanceIds) {
        this.processInstanceIds = processInstanceIds;
    }

    @Override
    public Object execute(CommandContext commandContext) {
        if (processInstanceIds == null) {
            throw new FlowableIllegalArgumentException("processInstanceIds is null");
        }

        if (processInstanceIds.isEmpty()) {
            throw new FlowableIllegalArgumentException("processInstanceIds is empty");
        }
        
        CommandContextUtil.getHistoryManager(commandContext).recordBulkDeleteProcessInstances(processInstanceIds);

        return null;
    }

}

View on GitHub (pinned to d6d39ce1c6)

Solutions

  1. Guard with an isEmpty() check before calling; skip the bulk delete when the list is empty.
  2. Log when the empty case occurs so batch jobs do not look failed when nothing matched.
  3. Fix upstream query logic if the empty result is unexpected (e.g. wrong historic-level configuration or time window).
  4. Only catch FlowableIllegalArgumentException if an empty batch is legitimately expected and ignorable.

Example fix

// before
historyService.bulkDeleteHistoricProcessInstances(ids); // may be empty
// after
if (ids != null && !ids.isEmpty()) {
    historyService.bulkDeleteHistoricProcessInstances(ids);
} else {
    logger.info("No historic process instances to delete");
}
Defensive patterns

Strategy: validation

Validate before calling

if (processInstanceIds == null || processInstanceIds.isEmpty()) {
    logger.info("Nothing to delete; skipping bulk historic delete");
    return;
}

Try / catch

try {
    historyService.bulkDeleteHistoricProcessInstances(ids);
} catch (FlowableIllegalArgumentException e) {
    if (e.getMessage().contains("is empty")) {
        logger.info("Empty id list; nothing deleted");
    } else {
        throw e;
    }
}

Prevention

When it happens

Trigger: Calling the bulk delete historic process instances API with an empty List (e.g. a query for completed instances returned nothing and the result was passed straight through to the bulk delete).

Common situations: Batch jobs that gather finished instance ids then delete their history — on the first run or when no instances match the filter, the list is empty and the call fails; filtering criteria too narrow; scheduler runs before data exists.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


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