flowable/flowable-engine · error · FlowableException

Could not resolve case instance id

Error message

Could not resolve case instance id

What it means

DefaultCmmnDynamicStateManager.movePlanItemInstanceState resolves the case instance from the builder's caseInstanceId before performing dynamic plan item state moves. If the builder has no case instance id, the state manager cannot locate the aggregate root to modify, and a FlowableException is thrown.

Source

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

import org.flowable.cmmn.model.PlanItemDefinition;
import org.flowable.common.engine.api.FlowableException;
import org.flowable.common.engine.impl.interceptor.CommandContext;

/**
 * @author Tijs Rademakers
 */
public class DefaultCmmnDynamicStateManager extends AbstractCmmnDynamicStateManager implements CmmnDynamicStateManager {
    
    public DefaultCmmnDynamicStateManager(CmmnEngineConfiguration cmmnEngineConfiguration) {
        super(cmmnEngineConfiguration);
    }

    @Override
    public void movePlanItemInstanceState(ChangePlanItemStateBuilderImpl changePlanItemStateBuilder, CommandContext commandContext) {
        String caseInstanceId = changePlanItemStateBuilder.getCaseInstanceId();
        
        if (caseInstanceId == null) {
            throw new FlowableException("Could not resolve case instance id");
        }
        
        CaseInstanceEntityManager caseInstanceEntityManager = CommandContextUtil.getCaseInstanceEntityManager(commandContext);
        CaseInstanceEntity caseInstance = caseInstanceEntityManager.findById(caseInstanceId);
        
        String originalCaseDefinitionId = caseInstance.getCaseDefinitionId();
        
        CaseInstanceChangeState caseInstanceChangeState = new CaseInstanceChangeState()
            .setCaseInstanceId(caseInstanceId)
            .setActivatePlanItemDefinitions(changePlanItemStateBuilder.getActivatePlanItemDefinitions())
            .setTerminatePlanItemDefinitions(changePlanItemStateBuilder.getTerminatePlanItemDefinitions())
            .setChangePlanItemDefinitionsToAvailable(changePlanItemStateBuilder.getChangeToAvailableStatePlanItemDefinitions())
            .setWaitingForRepetitionPlanItemDefinitions(changePlanItemStateBuilder.getWaitingForRepetitionPlanItemDefinitions())
            .setRemoveWaitingForRepetitionPlanItemDefinitions(changePlanItemStateBuilder.getRemoveWaitingForRepetitionPlanItemDefinitions())
            .setCaseVariables(changePlanItemStateBuilder.getCaseVariables())
            .setChildInstanceTaskVariables(changePlanItemStateBuilder.getChildInstanceTaskVariables());
        
        doMovePlanItemState(caseInstanceChangeState, originalCaseDefinitionId, commandContext);

View on GitHub (pinned to d6d39ce1c6)

Solutions

  1. Set a valid case instance id via changePlanItemStateBuilder.caseInstanceId(id) before changeState()
  2. Load the id from the CaseInstance query and assert it is non-null before building
  3. Check that the API path you use is cmmnRuntimeService.createChangePlanItemStateBuilder(caseInstanceId), which sets the id for you

Example fix

// before
runtimeService.createChangePlanItemStateBuilder(null) // or builder without caseInstanceId
    .movePlanItemInstanceState("pi1", "active").changeState();
// after
CaseInstance ci = runtimeService.createCaseInstanceQuery().caseInstanceBusinessKey("BK-1").singleResult();
runtimeService.createChangePlanItemStateBuilder(ci.getId())
    .movePlanItemInstanceState("pi1", "active").changeState();
Defensive patterns

Strategy: validation

Validate before calling

if (caseInstanceId == null || caseInstanceId.isEmpty()) throw new IllegalArgumentException("caseInstanceId required");

Type guard

boolean hasText(String s) { return s != null && !s.trim().isEmpty(); }

Try / catch

try { builder.changeState(); } catch (FlowableException e) { log.error("caseInstanceId missing: {}", e.getMessage()); }

Prevention

When it happens

Trigger: Building a ChangePlanItemStateBuilder without calling caseInstanceId(...) (or passing null) and then invoking changeState(); using a builder obtained from a service that failed to populate the id.

Common situations: Programmatic builder construction missing the id; the case instance id variable null because a previous lookup failed; copying builder setup code and dropping the caseInstanceId call.

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/cbc8698a5456f1b4. Report an issue: GitHub.