flowable/flowable-engine · error · FlowableIllegalArgumentException

query is null

Error message

query is null

What it means

Thrown by DeleteHistoricCaseInstancesUsingBatchesCmd.execute() when the HistoricCaseInstanceQuery passed to the command is null. The command needs a query to slice case instance ids into batches for deletion; without it no work can be planned.

Source

Thrown at modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/delete/DeleteHistoricCaseInstancesUsingBatchesCmd.java:64

 */
public class DeleteHistoricCaseInstancesUsingBatchesCmd implements Command<String> {

    protected HistoricCaseInstanceQueryImpl historicCaseInstanceQuery;
    protected int batchSize;
    protected boolean sequential;
    protected String batchName;

    public DeleteHistoricCaseInstancesUsingBatchesCmd(HistoricCaseInstanceQueryImpl query, int batchSize, String batchName, boolean sequential) {
        this.historicCaseInstanceQuery = query;
        this.batchSize = batchSize;
        this.batchName = batchName;
        this.sequential = sequential;
    }

    @Override
    public String execute(CommandContext commandContext) {
        if (historicCaseInstanceQuery == null) {
            throw new FlowableIllegalArgumentException("query is null");
        }

        if (batchSize <= 0) {
            throw new FlowableIllegalArgumentException("batchSize has to be larger than 0");
        }

        CmmnEngineConfiguration engineConfiguration = CommandContextUtil.getCmmnEngineConfiguration(commandContext);
        BatchService batchService = engineConfiguration.getBatchServiceConfiguration()
                .getBatchService();

        long numberOfCaseInstancesToDelete = historicCaseInstanceQuery.count();

        ObjectNode batchConfiguration = engineConfiguration.getObjectMapper().createObjectNode();
        batchConfiguration.put("numberOfInstances", numberOfCaseInstancesToDelete);
        batchConfiguration.put("batchSize", batchSize);
        if (sequential) {
            batchConfiguration.put("sequential", true);
        }

View on GitHub (pinned to d6d39ce1c6)

Solutions

  1. Construct a query first: historyService.createHistoricCaseInstanceQuery() (add filters as needed) and pass it to the command/management method
  2. Add a null check on the query before invoking the command
  3. Ensure the code path building the query always executes before the delete call

Example fix

// before
HistoricCaseInstanceQuery query = null;
managementService.bulkDeleteHistoricCaseInstances(query, 10, true);
// after
HistoricCaseInstanceQuery query = historyService.createHistoricCaseInstanceQuery().finished();
managementService.bulkDeleteHistoricCaseInstances(query, 10, true);
Defensive patterns

Strategy: type-guard

Validate before calling

if (historicCaseInstanceQuery == null) {
    historicCaseInstanceQuery = historyService.createHistoricCaseInstanceQuery();
}
managementService.bulkDeleteHistoricCaseInstances(historicCaseInstanceQuery, batchSize, sequential);

Type guard

boolean isUsableQuery(HistoricCaseInstanceQuery q) { return q != null; }

Try / catch

try { cmd.execute(commandContext); } catch (FlowableIllegalArgumentException e) { if (e.getMessage().equals("query is null")) { log.error("Pass a created HistoricCaseInstanceQuery", e); } throw e; }

Prevention

When it happens

Trigger: Calling the command (or the management-service method wrapping it) with historicCaseInstanceQuery == null, typically by passing an uninitialized variable or skipping query construction.

Common situations: Refactoring that left the query unassigned; conditional code paths where the query build step is skipped; API misuse assuming the command builds its own query.

Related errors


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