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
- Check where the planItemInstanceId value comes from and fix the code so it is populated before calling setLocalVariable.
- Add a null/blank check or Objects.requireNonNull on the id at your call site to fail with a clearer message.
- 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
- Resolve plan item ids via createPlanItemInstanceQuery() rather than manual state.
- Use Objects.requireNonNull on ids at API boundaries in your own code.
- Never store nullable ids for later engine calls; fail at the point of creation.
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
- Business status is null
- callback type is null
- callbackIds is null or empty
- Case definition keys is null
- caseInstance tenant id is null
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)