flowable/flowable-engine · error · FlowableIllegalArgumentException

planItemInstanceId is null

Error message

planItemInstanceId is null

What it means

SetLocalVariableCmd.execute() validates its inputs before touching the engine. If the planItemInstanceId passed to the set local variable command is null, it throws FlowableIllegalArgumentException immediately, since no plan item instance row can be looked up without an id. This is a fail-fast guard against a programming or API-usage mistake.

Solutions

  1. Check where the planItemInstanceId value comes from and fix the code so it is populated before calling setLocalVariable.
  2. Add a null/blank check or Objects.requireNonNull on the id at your call site to fail with a clearer message.
  3. If the id is genuinely unknown, first look up the plan item instance (e.g. createPlanItemInstanceQuery().planItemInstanceCaseInstanceId(...)) and use its id.

Example fix

// before
cmmnRuntimeService.setLocalVariable(planItemId, "status", value); // planItemId may be null
// after
Objects.requireNonNull(planItemId, "planItemId must be resolved before setting a local variable");
cmmnRuntimeService.setLocalVariable(planItemId, "status", value);
Defensive patterns

Strategy: validation

Validate before calling

if (planItemInstanceId == null || planItemInstanceId.isEmpty()) {
    throw new IllegalArgumentException("planItemInstanceId is required before calling setLocalVariable");
}

Type guard

boolean hasPlanItemId(String id) { return id != null && !id.isEmpty(); }

Try / catch

try {
    cmmnRuntimeService.setLocalVariable(planItemId, name, value);
} catch (FlowableIllegalArgumentException e) {
    log.error("Invalid argument for setLocalVariable: {}", e.getMessage());
}

Prevention

When it happens

Trigger: Calling CmmnRuntimeService.setLocalVariable(String planItemInstanceId, String variableName, Object value) (or any path that schedules SetLocalVariableCmd) with a null planItemInstanceId, e.g. a variable holding a plan item id that was never assigned or was lost upstream.

Common situations: Developers resolve the plan item id from a map/query result that returned null, pass a variable that failed initialization, or build the command programmatically in custom jobs/listeners where the id field is optional in their model but required by the engine.

Related errors


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

Appendix: source

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

/**
 * @author Tijs Rademakers
 */
public class SetLocalVariableCmd implements Command<Void> {
    
    protected String planItemInstanceId;
    protected String variableName;
    protected Object variableValue;
    
    public SetLocalVariableCmd(String planItemInstanceId, String variableName, Object variableValue) {
        this.planItemInstanceId = planItemInstanceId;
        this.variableName = variableName;
        this.variableValue = variableValue;
    }
    
    @Override
    public Void execute(CommandContext commandContext) {
        if (planItemInstanceId == null) {
            throw new FlowableIllegalArgumentException("planItemInstanceId is null");
        }
        if (variableName == null) {
            throw new FlowableIllegalArgumentException("variable name is null");
        }
     
        PlanItemInstanceEntity planItemInstanceEntity = CommandContextUtil.getPlanItemInstanceEntityManager(commandContext).findById(planItemInstanceId);
        if (planItemInstanceEntity == null) {
            throw new FlowableObjectNotFoundException("No plan item instance found for id " + planItemInstanceId, PlanItemInstanceEntity.class);
        }
        planItemInstanceEntity.setVariableLocal(variableName, variableValue);
        
        CommandContextUtil.getAgenda(commandContext).planEvaluateCriteriaOperation(planItemInstanceEntity.getCaseInstanceId());
        
        return null;
    }

}

View on GitHub (pinned to d6d39ce1c6)