flowable/flowable-engine · error · FlowableIllegalArgumentException

variableName is null

Error message

variableName is null

What it means

GetExecutionVariableCmd.execute() validates that variableName is non-null with FlowableIllegalArgumentException. Reading an execution variable requires naming it; a null name is rejected before any database access.

Solutions

  1. Check the variable name for null/blank before the call.
  2. Validate variable-name input at the service/REST layer and reject blank values.
  3. Ensure configuration supplying variable names is complete (see Flowable variable-name config keys).
  4. Log and fail fast with a clear message naming the missing configuration item.

Example fix

// before
Object v = runtimeService.getVariable(executionId, varName);
// after
if (varName == null || varName.isBlank()) {
    throw new IllegalArgumentException("variableName is required");
}
Object v = runtimeService.getVariable(executionId, varName);
Defensive patterns

Strategy: validation

Validate before calling

if (variableName == null || variableName.isBlank()) {
    throw new IllegalArgumentException("variableName is required");
}

Try / catch

try {
    runtimeService.getVariable(executionId, variableName);
} catch (FlowableIllegalArgumentException e) {
    // null/blank variable name: check config supplying the name
}

Prevention

When it happens

Trigger: Calling RuntimeService.getVariable(executionId, null) or getVariableLocal(executionId, null), usually when the variable name comes from unvalidated configuration or request data.

Common situations: Variable name held in a config property that is unset; dynamic key resolution returning null; copy/paste where the key literal was lost; mapping code dropping empty keys.

Related errors


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

Appendix: source

Thrown at modules/flowable-engine/src/main/java/org/flowable/engine/impl/cmd/GetExecutionVariableCmd.java:50

    private static final long serialVersionUID = 1L;
    protected String executionId;
    protected String variableName;
    protected boolean isLocal;

    public GetExecutionVariableCmd(String executionId, String variableName, boolean isLocal) {
        this.executionId = executionId;
        this.variableName = variableName;
        this.isLocal = isLocal;
    }

    @Override
    public Object execute(CommandContext commandContext) {
        if (executionId == null) {
            throw new FlowableIllegalArgumentException("executionId is null");
        }
        if (variableName == null) {
            throw new FlowableIllegalArgumentException("variableName is null");
        }

        ExecutionEntity execution = CommandContextUtil.getExecutionEntityManager(commandContext).findById(executionId);

        if (execution == null) {
            throw new FlowableObjectNotFoundException("execution " + executionId + " doesn't exist", Execution.class);
        }

        if (Flowable5Util.isFlowable5ProcessDefinitionId(commandContext, execution.getProcessDefinitionId())) {
            Flowable5CompatibilityHandler compatibilityHandler = Flowable5Util.getFlowable5CompatibilityHandler();
            return compatibilityHandler.getExecutionVariable(executionId, variableName, isLocal);
        }

        Object value;

        if (isLocal) {
            value = execution.getVariableLocal(variableName, false);
        } else {

View on GitHub (pinned to d6d39ce1c6)