flowable/flowable-engine · error · FlowableIllegalArgumentException
completedBefore is null
Error message
completedBefore is null
What it means
planItemInstanceCompletedBefore(Date) requires a non-null completedBefore Date and throws FlowableIllegalArgumentException 'completedBefore is null' when null is passed. Flowable validates the argument directly in the query builder so malformed criteria are rejected at construction, not at execution. A null bound cannot produce a valid predicate.
Solutions
- Pass a valid Date to the method.
- Wrap the call in a null check and skip the filter when the bound is unknown.
- Default the bound at the input boundary (e.g. new Date(0) or now).
- Catch FlowableIllegalArgumentException and construct the query without the completion filter.
Example fix
// before
query.planItemInstanceCompletedBefore(report.getCompletedBefore()); // may be null
// after
if (report.getCompletedBefore() != null) {
query.planItemInstanceCompletedBefore(report.getCompletedBefore());
} Defensive patterns
Strategy: validation
Validate before calling
if (completedBefore == null) {
throw new IllegalArgumentException("completedBefore must be a non-null Date");
}
query.planItemInstanceCompletedBefore(completedBefore); Type guard
boolean hasCompletionBound(Date d) { return d != null; } Try / catch
try {
query.planItemInstanceCompletedBefore(completedBefore);
} catch (FlowableIllegalArgumentException e) {
query = cmmnRuntimeService.createPlanItemInstanceQuery();
} Prevention
- Null-check completion bounds (often null for in-flight items) before querying
- Compose optional filters with conditional chaining
- Validate filter objects at the boundary before query building
- Cover historic-query filters with null-argument tests
When it happens
Trigger: Calling createPlanItemInstanceQuery().planItemInstanceCompletedBefore(null), usually when completion timestamps are missing (plan items not yet completed) or a request filter is absent.
Common situations: Historic/audit searches for completed plan items where the 'completed before' bound is optional; null from entities that never completed; JSON payloads omitting the field; copy-pasted filter code where one bound is unset.
Related errors
- activatedBefore is null
- disabledAfter is null
- disabledBefore is null
- enabledAfter is null
- enabledBefore is null
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/91e2273b04b23162.
Report an issue: GitHub.
Appendix: source
Thrown at modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/runtime/PlanItemInstanceQueryImpl.java:519
}
@Override
public PlanItemInstanceQuery planItemInstanceLastSuspendedAfter(Date suspendedAfter) {
if (suspendedAfter == null) {
throw new FlowableIllegalArgumentException("suspendedAfter is null");
}
if (inOrStatement) {
this.currentOrQueryObject.lastSuspendedAfter = suspendedAfter;
} else {
this.lastSuspendedAfter = suspendedAfter;
}
return this;
}
@Override
public PlanItemInstanceQuery planItemInstanceCompletedBefore(Date completedBefore) {
if (completedBefore == null) {
throw new FlowableIllegalArgumentException("completedBefore is null");
}
if (inOrStatement) {
this.currentOrQueryObject.completedBefore = completedBefore;
} else {
this.completedBefore = completedBefore;
}
return this;
}
@Override
public PlanItemInstanceQuery planItemInstanceCompletedAfter(Date completedAfter) {
if (completedAfter == null) {
throw new FlowableIllegalArgumentException("completedAfter is null");
}
if (inOrStatement) {
this.currentOrQueryObject.completedAfter = completedAfter;
} else {
this.completedAfter = completedAfter;View on GitHub (pinned to d6d39ce1c6)