flowable/flowable-engine · error · FlowableIllegalArgumentException

completedAfter is null

Error message

completedAfter is null

What it means

Flowable throws FlowableIllegalArgumentException when planItemInstanceCompletedAfter(Date) is called with a null Date argument. Query parameter methods validate their inputs eagerly so an invalid query fails at construction time rather than producing a broken SQL query or silent wrong results. Passing null means the caller has no completedAfter timestamp to filter on and should simply not call the method.

Solutions

  1. Ensure a non-null Date is passed: resolve the value from user input or compute a default before calling planItemInstanceCompletedAfter.
  2. Only call the method when the value exists (null-check at the call site); omitting the call means no filter on this attribute.
  3. If input is a string, parse it with a checked date parser and reject invalid/empty input before building the query.
  4. Wrap the query-building code in a try-catch for FlowableIllegalArgumentException to fail fast with a clear client-facing message.

Example fix

// before
Date completedAfter = params.get("completedAfter"); // may be null
query.planItemInstanceCompletedAfter(completedAfter);
// after
Date completedAfter = params.get("completedAfter");
if (completedAfter != null) {
    query.planItemInstanceCompletedAfter(completedAfter);
}
Defensive patterns

Strategy: validation

Validate before calling

if (completedAfter == null) {
    throw new IllegalArgumentException("completedAfter must be provided or the filter must be omitted");
}
query.planItemInstanceCompletedAfter(completedAfter);

Type guard

boolean hasCompletedAfter = (completedAfter != null);

Try / catch

try {
    query.planItemInstanceCompletedAfter(completedAfter);
} catch (FlowableIllegalArgumentException e) {
    if (e.getMessage().contains("completedAfter")) {
        throw new BadRequestException("completedAfter date filter must not be null");
    }
    throw e;
}

Prevention

When it happens

Trigger: Calling runtimeService.createPlanItemInstanceQuery().planItemInstanceCompletedAfter(null), typically when the date comes from an optional request parameter or deserialized DTO field that was not set.

Common situations: REST/UI layer passes through an unvalidated 'completedAfter' query param that is absent or null; a Java bean built from JSON where the field was omitted; a default-initialization bug where a Calendar/Date conversion returned null.

Related errors


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

Appendix: source

Thrown at modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/runtime/PlanItemInstanceQueryImpl.java:532

    }

    @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;
        }
        return this;
    }

    @Override
    public PlanItemInstanceQuery planItemInstanceOccurredBefore(Date occurredBefore) {
        if (occurredBefore == null) {
            throw new FlowableIllegalArgumentException("occurredBefore is null");
        }
        if (inOrStatement) {
            this.currentOrQueryObject.occurredBefore = occurredBefore;
        } else {
            this.occurredBefore = occurredBefore;

View on GitHub (pinned to d6d39ce1c6)