flowable/flowable-engine · error · FlowableObjectNotFoundException

plan item instance doesn't exist

Error message

plan item instance ${planItemInstanceId} doesn't exist

What it means

HasPlanItemInstanceVariableCmd.execute throws FlowableObjectNotFoundException when the given planItemInstanceId does not match any plan item instance in the runtime tables. The ids were valid non-null values, but findById returned null, so the engine reports the plan item instance as nonexistent rather than returning false for the variable check.

Solutions

  1. Look up the plan item first via a PlanItemInstanceQuery and handle absence
  2. If the plan item may have completed, query cmmnHistoryService plan item instance data instead
  3. Validate the id source and database/schema targeting

Example fix

// before
boolean has = cmmnRuntimeService.hasPlanItemVariable(piId, "flag");
// after
PlanItemInstance pii = cmmnRuntimeService.createPlanItemInstanceQuery()
    .planItemInstanceId(piId).singleResult();
boolean has = pii != null && cmmnRuntimeService.hasPlanItemVariable(piId, "flag");
Defensive patterns

Strategy: try-catch

Validate before calling

PlanItemInstance pii = cmmnRuntimeService.createPlanItemInstanceQuery()
    .planItemInstanceId(planItemInstanceId).singleResult();
if (pii == null) {
    // plan item absent; use history if needed
}

Type guard

boolean planItemExists(CmmnRuntimeService rs, String id) {
    return id != null && rs.createPlanItemInstanceQuery().planItemInstanceId(id).singleResult() != null;
}

Try / catch

try {
    return cmmnRuntimeService.hasPlanItemVariable(piId, variableName);
} catch (FlowableObjectNotFoundException e) {
    log.warn("Plan item instance {} not found", piId);
    return false;
}

Prevention

When it happens

Trigger: Calling hasPlanItemVariable with an id of a plan item that already completed/terminated, a malformed id, or an id from a different case/engine instance.

Common situations: Checking variables after the stage/plan item moved to a terminal state, stale ids cached in application state, tests with hard-coded ids, pointing at a different database environment.

Understand the failure class

Background: "Not found" and "does not exist" errors: why "Task not found", "No such folder", and "Can't find" fire when a lookup comes back empty — this error's family across 14 libraries.

Related errors


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

Appendix: source

Thrown at modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/cmd/HasPlanItemInstanceVariableCmd.java:48

    public HasPlanItemInstanceVariableCmd(String caseInstanceId, String variableName) {
        this.planItemInstanceId = caseInstanceId;
        this.variableName = variableName;
    }

    @Override
    public Boolean execute(CommandContext commandContext) {
        if (planItemInstanceId == null) {
            throw new FlowableIllegalArgumentException("planItemInstanceId is null");
        }
        if (variableName == null) {
            throw new FlowableIllegalArgumentException("variableName is null");
        }

        PlanItemInstanceEntity planItemInstance = CommandContextUtil.getPlanItemInstanceEntityManager(commandContext).findById(planItemInstanceId);

        if (planItemInstance == null) {
            throw new FlowableObjectNotFoundException("plan item instance " + planItemInstanceId + " doesn't exist", PlanItemInstance.class);
        }
        return planItemInstance.hasVariableLocal(variableName);
    }
}

View on GitHub (pinned to d6d39ce1c6)