flowable/flowable-engine · error · FlowableIllegalArgumentException
decisionTableReferenceKey expression resolves to an empty va
Error message
decisionTableReferenceKey expression resolves to an empty value: ${decisionKeyValue} What it means
The decisionTableReferenceKey expression resolved successfully but produced null or an empty string. Flowable requires a concrete decision key to look up the DMN decision, so it throws FlowableIllegalArgumentException. This differs from error 2051: the type is fine, the value is empty.
Source
Thrown at modules/flowable-engine/src/main/java/org/flowable/engine/impl/bpmn/behavior/DmnActivityBehavior.java:94
ExpressionManager expressionManager = processEngineConfiguration.getExpressionManager();
if (processEngineConfiguration.isEnableProcessDefinitionInfoCache()) {
ObjectNode taskElementProperties = BpmnOverrideContext.getBpmnOverrideElementProperties(task.getId(), execution.getProcessDefinitionId());
activeDecisionKey = DynamicPropertyUtil.getActiveValue(activeDecisionKey, DynamicBpmnConstants.DMN_TASK_DECISION_TABLE_KEY, taskElementProperties);
}
String finalDecisionKeyValue = null;
Object decisionKeyValue = expressionManager.createExpression(activeDecisionKey).getValue(execution);
if (decisionKeyValue != null) {
if (decisionKeyValue instanceof String) {
finalDecisionKeyValue = (String) decisionKeyValue;
} else {
throw new FlowableIllegalArgumentException("decisionTableReferenceKey expression does not resolve to a string: " + decisionKeyValue);
}
}
if (finalDecisionKeyValue == null || finalDecisionKeyValue.length() == 0) {
throw new FlowableIllegalArgumentException("decisionTableReferenceKey expression resolves to an empty value: " + decisionKeyValue);
}
DmnDecisionService ruleService = CommandContextUtil.getDmnRuleService();
ExecuteDecisionBuilder executeDecisionBuilder = ruleService.createExecuteDecisionBuilder()
.decisionKey(finalDecisionKeyValue)
.instanceId(execution.getProcessInstanceId())
.executionId(execution.getId())
.activityId(task.getId())
.variables(execution.getVariables())
.tenantId(execution.getTenantId());
applyFallbackToDefaultTenant(execution, executeDecisionBuilder);
applyParentDeployment(execution, executeDecisionBuilder, processEngineConfiguration);
DecisionExecutionAuditContainer decisionExecutionAuditContainer = executeDecisionBuilder.executeWithAuditTrail();
if (decisionExecutionAuditContainer.isFailed()) {
View on GitHub (pinned to d6d39ce1c6)
Solutions
- Set the decision-key variable before the DMN task executes, or start the process with it: runtimeService.startProcessInstanceByKey(proc, vars with decisionKeyVar)
- Correct the variable name in the expression (check case) so it points at an existing variable
- Add a default value or guard task/condition that fails fast if the variable is missing
- Reorder the flow so any service task that computes the key runs before the DMN task
Example fix
// before
Map<String, Object> vars = new HashMap<>(); // decisionKeyVar never set
runtimeService.startProcessInstanceByKey("myProcess", vars);
// after
Map<String, Object> vars = new HashMap<>();
vars.put("decisionKeyVar", "myDecisionTable");
runtimeService.startProcessInstanceByKey("myProcess", vars); Defensive patterns
Strategy: validation
Validate before calling
Object key = execution.getVariable("decisionKeyVar");
if (key == null || key.toString().isEmpty()) {
throw new IllegalStateException("Decision key variable must be set and non-empty before the DMN task");
} Type guard
static boolean isPresent(String s) { return s != null && !s.isEmpty(); } Try / catch
try {
runtimeService.startProcessInstanceByKey("myProcess", vars);
} catch (FlowableIllegalArgumentException e) {
if (e.getMessage().contains("resolves to an empty value")) {
// restart with explicit decision key variable
} else throw e;
} Prevention
- Start process instances with the decision key pre-populated
- Verify expression variable names for typos/case
- Set the variable on every branch that can reach the DMN task
- Add an entry execution listener that fails fast when the key is absent
When it happens
Trigger: The expression references a process variable that is null or "" at the time the DMN task executes (variable never set, removed, or set after the task runs); the expression returns an empty result of an EL evaluation (e.g. ${emptyVar}).
Common situations: Asynchronous boundary or parallel branch where the variable is set in another path that hasn't completed; typo in the variable name inside the expression so it silently resolves to null; caller forgot to pass the decision key when starting the process instance.
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
- Could not execute decision: no externalRef defined for ${pla
- byte array for resource '${resourceName}' is null
- Could not resolve key for: ${eventDefinitionKey} in ${execut
- decisionTableReferenceKey expression does not resolve to a s
- Unable to resolve expression value for ${value} in ${planIte
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/db4029daae677929.
Report an issue: GitHub.