flowable/flowable-engine · error · FlowableObjectNotFoundException

plan item instance ${planItemInstanceId} 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.

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)

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.