flowable/flowable-engine · error · FlowableIllegalArgumentException

selectCaseInstanceEagerFetchPlanItemInstances needs either…

Error message

selectCaseInstanceEagerFetchPlanItemInstances needs either caseInstanceId or planItemInstanceId

What it means

Thrown by MybatisCaseInstanceDataManagerImpl.findCaseInstanceEntityEagerFetchPlanItemInstances when neither caseInstanceId nor planItemInstanceId was supplied. The eager-fetch query needs at least one of these parameters to identify which case instance to load with its plan item instances.

Solutions

  1. Pass a non-null caseInstanceId or planItemInstanceId to findById
  2. Ensure the calling code actually resolved one of the two identifiers before doing the eager fetch

Example fix

// before
caseInstanceEntityManager.findById(null, null);
// after
caseInstanceEntityManager.findById(caseInstanceId, null);
Defensive patterns

Strategy: validation

Validate before calling

if (caseInstanceId == null && planItemInstanceId == null) {
    throw new IllegalArgumentException("Either caseInstanceId or planItemInstanceId is required");
}

Type guard

boolean hasIdentifier = caseInstanceId != null || planItemInstanceId != null;

Try / catch

try {
    return dataManager.findCaseInstanceEntityEagerFetchPlanItemInstances(caseInstanceId, planItemInstanceId);
} catch (FlowableIllegalArgumentException e) {
    // resolve an identifier from the caller context first
}

Prevention

When it happens

Trigger: Calling findById(null, null) (or equivalent) on the case instance data manager with both parameters null.

Common situations: Custom engine extensions that pass through null values from an upper layer; refactored code where one of the two identifiers became null due to an upstream bug.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


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

Appendix: source

Thrown at modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/persistence/entity/data/impl/MybatisCaseInstanceDataManagerImpl.java:91

    public CaseInstanceEntity findCaseInstanceEntityEagerFetchPlanItemInstances(String caseInstanceId, String planItemInstanceId) {

        // Could have been fetched before
        EntityCache entityCache = getEntityCache();
        CaseInstanceEntity cachedCaseInstanceEntity = entityCache.findInCache(getManagedEntityClass(), caseInstanceId);
        if (cachedCaseInstanceEntity != null) {
            return cachedCaseInstanceEntity;
        }

        // Not in cache
        HashMap<String, Object> params = new HashMap<>(1);
        if (caseInstanceId != null) {
            params.put("caseInstanceId", caseInstanceId);
        } else if (planItemInstanceId != null) {
            params.put("planItemInstanceId", planItemInstanceId);
        }

        if (params.isEmpty()) {
            throw new FlowableIllegalArgumentException("selectCaseInstanceEagerFetchPlanItemInstances needs either caseInstanceId or planItemInstanceId");
        }

        // The case instance will be fetched and will have all plan item instances in the childPlanItemInstances property.
        // Those children need to be properly moved to the correct parent
        CaseInstanceEntityImpl caseInstanceEntity = (CaseInstanceEntityImpl) getDbSqlSession().selectOne("selectCaseInstanceEagerFetchPlanItemInstances", params);

        if (caseInstanceEntity != null) {
            List<PlanItemInstanceEntity> allPlanItemInstances = caseInstanceEntity.getChildPlanItemInstances();
            ArrayList<PlanItemInstanceEntity> directPlanItemInstances = new ArrayList<>();
            HashMap<String, PlanItemInstanceEntity> planItemInstanceMap = new HashMap<>(allPlanItemInstances.size());

            // Map all plan item instances to its id
            for (PlanItemInstanceEntity planItemInstanceEntity : allPlanItemInstances) {

                PlanItemInstanceEntity currentPlanItemInstanceEntity = planItemInstanceEntity;

                // If it's already in the cache, it has precedence on the fetched one
                PlanItemInstanceEntity planItemInstanceFromCache = entityCache.findInCache(PlanItemInstanceEntityImpl.class, planItemInstanceEntity.getId());

View on GitHub (pinned to d6d39ce1c6)