flowable/flowable-engine · error · FlowableIllegalArgumentException

terminatedBefore is null

Error message

terminatedBefore is null

What it means

Flowable throws FlowableIllegalArgumentException when planItemInstanceTerminatedBefore(Date) receives a null Date. The query API validates each criterion eagerly so malformed queries surface immediately at build time rather than as SQL errors. A null date is not a valid filter; omit the call instead.

Solutions

  1. Pass a concrete Date obtained from validated input.
  2. Skip the method call when no terminatedBefore filter is needed.
  3. Validate and convert date strings with explicit error handling before query building.
  4. Wrap query construction in try-catch for FlowableIllegalArgumentException to fail fast.

Example fix

// before
query.planItemInstanceTerminatedBefore(filter.getTerminatedBefore()); // may be null
// after
if (filter.getTerminatedBefore() != null) {
    query.planItemInstanceTerminatedBefore(filter.getTerminatedBefore());
}
Defensive patterns

Strategy: validation

Validate before calling

if (terminatedBefore == null) {
    throw new IllegalArgumentException("terminatedBefore must be non-null; omit the filter instead");
}
query.planItemInstanceTerminatedBefore(terminatedBefore);

Type guard

boolean hasTerminatedBefore = (terminatedBefore != null);

Try / catch

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

Prevention

When it happens

Trigger: Calling createPlanItemInstanceQuery().planItemInstanceTerminatedBefore(null), e.g. when the terminated-before timestamp is sourced from an unset request field.

Common situations: Optional 'terminatedBefore' filter left empty in a dashboard search form; DTO field absent after JSON deserialization; null returned by a date-parsing helper.

Related errors


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

Appendix: source

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

    }

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

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

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

View on GitHub (pinned to d6d39ce1c6)