flowable/flowable-engine · error · FlowableIllegalArgumentException

after time is null

Error message

after time is null

What it means

FlowableIllegalArgumentException thrown by HistoricCaseInstanceQueryImpl.finishedAfter(Date) in flowable-cmmn-engine when the given date is null. The query API refuses to register a 'finished after' filter without a concrete timestamp, because a null date cannot be translated into a meaningful SQL comparison on the finished-time column of historic case instances. Fail fast at query-build time rather than producing broken SQL at query-execution time.

Source

Thrown at modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/history/HistoricCaseInstanceQueryImpl.java:608

    }
    
    @Override
    public HistoricCaseInstanceQueryImpl finishedBefore(Date beforeTime) {
        if (beforeTime == null) {
            throw new FlowableIllegalArgumentException("before time is null");
        }
        if (inOrStatement) {
            this.currentOrQueryObject.finishedBefore = beforeTime;
        } else {
            this.finishedBefore = beforeTime;
        }
        return this;
    }
    
    @Override
    public HistoricCaseInstanceQueryImpl finishedAfter(Date afterTime) {
        if (afterTime == null) {
            throw new FlowableIllegalArgumentException("after time is null");
        }
        if (inOrStatement) {
            this.currentOrQueryObject.finishedAfter = afterTime;
        } else {
            this.finishedAfter = afterTime;
        }
        return this;
    }

    @Override
    public HistoricCaseInstanceQueryImpl startedBefore(Date beforeTime) {
        if (beforeTime == null) {
            throw new FlowableIllegalArgumentException("before time is null");
        }
        if (inOrStatement) {
            this.currentOrQueryObject.startedBefore = beforeTime;
        } else {
            this.startedBefore = beforeTime;

View on GitHub (pinned to d6d39ce1c6)

Solutions

  1. Ensure a non-null Date is passed: supply a concrete timestamp before calling finishedAfter().
  2. If the filter is optional, skip calling finishedAfter() entirely when the value is null instead of passing null.
  3. Validate/parse date inputs (e.g. from REST params) and reject or default them before building the query.

Example fix

// before
query.finishedAfter(request.getFinishedAfter()); // getFinishedAfter() may return null

// after
if (request.getFinishedAfter() != null) {
    query.finishedAfter(request.getFinishedAfter());
}
Defensive patterns

Strategy: validation

Validate before calling

if (finishedAfter == null) {
    throw new IllegalArgumentException("finishedAfter must be provided when filtering by finish time");
}
query.finishedAfter(finishedAfter);

Type guard

boolean hasFinishedAfter(Date d) { return d != null; }

Try / catch

try {
    query.finishedAfter(afterTime);
} catch (FlowableIllegalArgumentException e) {
    if (e.getMessage().contains("after time is null")) {
        log.warn("Ignoring finishedAfter filter: no date supplied");
        query = baseQuery(); // rebuild without the filter
    } else {
        throw e;
    }
}

Prevention

When it happens

Trigger: Calling cmmnHistoryService.createHistoricCaseInstanceQuery().finishedAfter(null); also occurs when calling finishedAfter(variable) inside an or() block and the variable resolving to the Date is null (the null check happens before the inOrStatement branch).

Common situations: Developers pass a Date obtained from an optional request parameter, a config value, or a computed value (e.g. endDate of a still-running period) without checking for null; REST/API layers that deserialize a missing 'finishedAfter' field into null and forward it directly into the query builder.

Related errors


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