flowable/flowable-engine · error · FlowableIllegalArgumentException

variables is empty

Error message

variables is empty

What it means

SetLocalVariablesCmd.execute() throws FlowableIllegalArgumentException when the variables map is empty (after null checks on id and map). The engine refuses to execute a variable-set command that would change nothing.

Source

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

    
    protected String planItemInstanceId;
    protected Map<String, Object> variables;
    
    public SetLocalVariablesCmd(String planItemInstanceId, Map<String, Object> variables) {
        this.planItemInstanceId = planItemInstanceId;
        this.variables = variables;
    }
    
    @Override
    public Void execute(CommandContext commandContext) {
        if (planItemInstanceId == null) {
            throw new FlowableIllegalArgumentException("planItemInstanceId is null");
        }
        if (variables == null) {
            throw new FlowableIllegalArgumentException("variables is null");
        }
        if (variables.isEmpty()) {
            throw new FlowableIllegalArgumentException("variables is empty");
        }
     
        PlanItemInstanceEntity planItemInstanceEntity = CommandContextUtil.getPlanItemInstanceEntityManager(commandContext).findById(planItemInstanceId);
        if (planItemInstanceEntity == null) {
            throw new FlowableObjectNotFoundException("No plan item instance found for id " + planItemInstanceId, PlanItemInstanceEntity.class);
        }
        planItemInstanceEntity.setVariablesLocal(variables);
        
        CommandContextUtil.getAgenda(commandContext).planEvaluateCriteriaOperation(planItemInstanceEntity.getCaseInstanceId());
        
        return null;
    }

}

View on GitHub (pinned to d6d39ce1c6)

Solutions

  1. Guard the call with !variables.isEmpty() and skip it when there is nothing to set.
  2. Only build/submit the command when at least one variable needs to be written.
  3. If a no-op is intended, simply do not call the API.

Example fix

// before
cmmnRuntimeService.setLocalVariables(planItemId, applicableVars); // may be empty
// after
if (!applicableVars.isEmpty()) {
    cmmnRuntimeService.setLocalVariables(planItemId, applicableVars);
}
Defensive patterns

Strategy: validation

Validate before calling

if (variables == null || variables.isEmpty()) {
    return; // nothing to set
}

Type guard

boolean isNonEmpty(Map<String, ?> m) { return m != null && !m.isEmpty(); }

Try / catch

try {
    cmmnRuntimeService.setLocalVariables(planItemId, vars);
} catch (FlowableIllegalArgumentException e) {
    log.error("setLocalVariables rejected: {}", e.getMessage());
}

Prevention

When it happens

Trigger: Calling CmmnRuntimeService.setLocalVariables(planItemInstanceId, new HashMap<>()) or with a map whose entries were all filtered out before the call.

Common situations: Computed delta maps ending up empty; loops that unconditionally invoke the setter per plan item even when no variable applies to that one.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


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