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

  1. Pass a valid Date to the method.
  2. Wrap the call in a null check and skip the filter when the bound is unknown.
  3. Default the bound at the input boundary (e.g. new Date(0) or now).
  4. 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

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


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)