flowable/flowable-engine · error · FlowableIllegalArgumentException

Stage instance id is null

Error message

Stage instance id is null

What it means

Flowable's PlanItemInstanceQuery.stageInstanceId() throws FlowableIllegalArgumentException when stageInstanceId is null. This filter narrows plan item instances to those inside a specific stage; the setter validates the argument eagerly so malformed queries never reach the database.

Solutions

  1. Pass a valid stage instance id (resolve it via PlanItemRuntimeService for the stage plan item)
  2. Only call stageInstanceId(id) when the id is non-null; at root level, omit the filter
  3. Null-check the PlanItemInstance representing the stage before using its getId()

Example fix

// before
query.stageInstanceId(stage.getId()); // stage may be null

// after
if (stage != null) {
    query.stageInstanceId(stage.getId());
}
Defensive patterns

Strategy: validation

Validate before calling

if (stageInstanceId != null && !stageInstanceId.isBlank()) {
    query.stageInstanceId(stageInstanceId);
}

Type guard

boolean isPresent(String id) { return id != null && !id.isBlank(); }

Try / catch

try {
    query.stageInstanceId(stageInstanceId);
} catch (FlowableIllegalArgumentException e) {
    log.warn("Stage filter skipped: {}", e.getMessage());
}

Prevention

When it happens

Trigger: Calling stageInstanceId(null), e.g. when the stage instance id comes from a plan item lookup that returned null, an unset variable, or an absent request parameter.

Common situations: Navigating a case hierarchy where the code assumes a parent stage exists; querying at case root level where no stage is active; UI code passing a cleared selection field.

Related errors


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

Appendix: source

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

        if (caseInstanceIds == null) {
            throw new FlowableIllegalArgumentException("Set of case instance ids is null");
        }
        if (caseInstanceIds.isEmpty()) {
            throw new FlowableIllegalArgumentException("Set of case instance ids is empty");
        }

        if (inOrStatement) {
            this.currentOrQueryObject.caseInstanceIds = caseInstanceIds;
        } else {
            this.caseInstanceIds = caseInstanceIds;
        }
        return this;
    }

    @Override
    public PlanItemInstanceQuery stageInstanceId(String stageInstanceId) {
        if (stageInstanceId == null) {
            throw new FlowableIllegalArgumentException("Stage instance id is null");
        }
        if (inOrStatement) {
            this.currentOrQueryObject.stageInstanceId = stageInstanceId;
        } else {
            this.stageInstanceId = stageInstanceId;
        }
        return this;
    }
    
    @Override
    public PlanItemInstanceQuery planItemInstanceId(String planItemInstanceId) {
        if (planItemInstanceId == null) {
            throw new FlowableIllegalArgumentException("Plan Item instance id is null");
        }
        if (inOrStatement) {
            this.currentOrQueryObject.planItemInstanceId = planItemInstanceId;
        } else {
            this.planItemInstanceId = planItemInstanceId;

View on GitHub (pinned to d6d39ce1c6)