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
- Ensure a non-null Date is passed: supply a concrete timestamp before calling finishedAfter().
- If the filter is optional, skip calling finishedAfter() entirely when the value is null instead of passing null.
- 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
- Wrap optional date filters in helper methods that apply them only when non-null.
- Use java.util.Optional<Date> for nullable filter inputs and ifPresent(query::finishedAfter).
- Add bean-validation (@NotNull) on DTO fields carrying query time bounds.
- Never call query-builder methods directly with values read straight from request parameters.
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
- user id is null
- Null planItemInstance passed
- planItemDefinitionIds is null
- involvedUser is null
- userId is null
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/8a5d063391c19cf6.
Report an issue: GitHub.