flowable/flowable-engine · error · FlowableIllegalArgumentException

variables is empty

Error message

variables is empty

What it means

Thrown by SetVariablesAsyncCmd.execute when the variables map is non-null but empty. The command requires at least one variable to write, so an empty map is rejected with FlowableIllegalArgumentException to avoid scheduling a pointless async job.

Source

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

    
    protected String caseInstanceId;
    protected Map<String, Object> variables;
    
    public SetVariablesAsyncCmd(String caseInstanceId, Map<String, Object> variables) {
        this.caseInstanceId = caseInstanceId;
        this.variables = variables;
    }
    
    @Override
    public Void execute(CommandContext commandContext) {
        if (caseInstanceId == null) {
            throw new FlowableIllegalArgumentException("caseInstanceId 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);
        CaseInstanceEntity caseInstanceEntity = cmmnEngineConfiguration.getCaseInstanceEntityManager().findById(caseInstanceId);
        if (caseInstanceEntity == null) {
            throw new FlowableObjectNotFoundException("No case instance found for id " + caseInstanceId, CaseInstanceEntity.class);
        }
        
        for (String variableName : variables.keySet()) {
            addVariable(false, caseInstanceId, null, variableName, variables.get(variableName), caseInstanceEntity.getTenantId(), 
                    cmmnEngineConfiguration.getVariableServiceConfiguration().getVariableService());
        }
        
        createSetAsyncVariablesJob(caseInstanceEntity, cmmnEngineConfiguration);
        
        return null;
    }

View on GitHub (pinned to d6d39ce1c6)

Solutions

  1. Skip the call when the map is empty instead of invoking the API
  2. Validate map non-empty before calling and fail earlier with a clearer message
  3. Fix the upstream collection building so it produces the expected entries

Example fix

// before
if (!vars.isEmpty()) {
    cmmnRuntimeService.setVariablesAsync(caseId, vars);
}
// after (explicit guard at the API boundary)
if (vars == null || vars.isEmpty()) {
    throw new IllegalArgumentException("At least one variable is required");
}
cmmnRuntimeService.setVariablesAsync(caseId, vars);
Defensive patterns

Strategy: validation

Validate before calling

if (variables == null || variables.isEmpty()) {
    throw new IllegalArgumentException("At least one variable is required");
}

Type guard

boolean hasVariables(Map<String, Object> vars) { return vars != null && !vars.isEmpty(); }

Try / catch

try {
    cmmnRuntimeService.setVariablesAsync(caseInstanceId, vars);
} catch (FlowableIllegalArgumentException e) {
    log.error("No variables provided: {}", e.getMessage());
}

Prevention

When it happens

Trigger: Calling setVariablesAsync with an empty Map, typically from a filtered/transformed collection that ended up with zero entries.

Common situations: Input payload with no variables, all entries filtered out by validation logic, batch job iterating over cases with nothing to set.

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