flowable/flowable-engine · error · FlowableIllegalArgumentException

unavailableBefore is null

Error message

unavailableBefore is null

What it means

Thrown by PlanItemInstanceQueryImpl.planItemInstanceLastUnavailableBefore when the unavailableBefore Date is null. The builder requires a concrete date for this upper bound on the last-unavailable timestamp and fails fast on null.

Solutions

  1. Pass a valid java.util.Date for the bound.
  2. Only invoke the filter when the date is non-null; combine with planItemInstanceLastUnavailableAfter for a range.
  3. Validate inputs at the boundary and reject malformed dates with a clear error instead of passing null down.

Example fix

// before
query.planItemInstanceLastUnavailableBefore(end); // end may be null
// after
if (end != null) {
    query.planItemInstanceLastUnavailableBefore(end);
}
Defensive patterns

Strategy: validation

Validate before calling

if (unavailableBefore != null) {
    planItemInstanceQuery.planItemInstanceLastUnavailableBefore(unavailableBefore);
}

Type guard

boolean isPresent(Date d) {
    return d != null;
}

Try / catch

try {
    query.planItemInstanceLastUnavailableBefore(unavailableBefore);
} catch (FlowableIllegalArgumentException e) {
    if (e.getMessage().contains("unavailableBefore is null")) {
        // omit the filter or reject the input
    } else {
        throw e;
    }
}

Prevention

When it happens

Trigger: Calling planItemInstanceLastUnavailableBefore(null), typically via a nullable variable feeding a time-range filter.

Common situations: Optional end-date filters in monitoring/reporting UIs; null results from lenient date parsing of invalid strings.

Related errors


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

Appendix: source

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

    }

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

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

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

View on GitHub (pinned to d6d39ce1c6)