flowable/flowable-engine · error · FlowableIllegalArgumentException
variables is empty
Error message
variables is empty
What it means
SetLocalVariablesAsyncCmd.execute() throws FlowableIllegalArgumentException when the variables map is empty. An empty map would produce no work, so the engine treats it as invalid input rather than scheduling a pointless async job.
Source
Thrown at modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/cmd/SetLocalVariablesAsyncCmd.java:44
protected String planItemInstanceId;
protected Map<String, Object> variables;
public SetLocalVariablesAsyncCmd(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");
}
CmmnEngineConfiguration cmmnEngineConfiguration = CommandContextUtil.getCmmnEngineConfiguration(commandContext);
PlanItemInstanceEntity planItemInstanceEntity = cmmnEngineConfiguration.getPlanItemInstanceEntityManager().findById(planItemInstanceId);
if (planItemInstanceEntity == null) {
throw new FlowableObjectNotFoundException("No plan item instance found for id " + planItemInstanceId, PlanItemInstanceEntity.class);
}
for (String variableName : variables.keySet()) {
addVariable(true, planItemInstanceEntity.getCaseInstanceId(), planItemInstanceEntity.getId(), variableName, variables.get(variableName),
planItemInstanceEntity.getTenantId(), cmmnEngineConfiguration.getVariableServiceConfiguration().getVariableService());
}
createSetAsyncVariablesJob(planItemInstanceEntity, cmmnEngineConfiguration);
return null;
}
View on GitHub (pinned to d6d39ce1c6)
Solutions
- Check variables.isEmpty() at the call site and skip the async call when there is nothing to set.
- Only call setLocalVariablesAsync when at least one variable must be changed.
- If the intent is 'no-op', restructure the caller so the command is never scheduled.
Example fix
// before
cmmnRuntimeService.setLocalVariablesAsync(planItemId, changedVars); // may be empty
// after
if (!changedVars.isEmpty()) {
cmmnRuntimeService.setLocalVariablesAsync(planItemId, changedVars);
} Defensive patterns
Strategy: validation
Validate before calling
if (variables == null || variables.isEmpty()) {
return; // nothing to set; skip the async command
} Type guard
boolean isNonEmpty(Map<String, ?> m) { return m != null && !m.isEmpty(); } Try / catch
try {
cmmnRuntimeService.setLocalVariablesAsync(planItemId, vars);
} catch (FlowableIllegalArgumentException e) {
log.error("setLocalVariablesAsync rejected: {}", e.getMessage());
} Prevention
- Skip the async call when the computed variable delta is empty.
- Treat empty-variable operations as no-ops in calling code.
- Unit-test batch paths where filters may remove all entries.
When it happens
Trigger: Calling CmmnRuntimeService.setLocalVariablesAsync(planItemInstanceId, Collections.emptyMap()) or with a map filtered down to zero entries before the call.
Common situations: Batch code that computes variable deltas and unconditionally calls the async setter even when nothing changed; upstream filtering removing all entries.
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
- variables is empty
- variables is empty
- variables is empty
- Could not find an app definition with id '<appDefinitionId>
- Could not find a deployment with id '<deploymentId>
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/19fb26d96118b610.
Report an issue: GitHub.