{"record":{"id":"db4029daae677929","repo":"flowable/flowable-engine","slug":"decisiontablereferencekey-expression-resolves-to-a","errorCode":null,"errorMessage":"decisionTableReferenceKey expression resolves to an empty value: ${decisionKeyValue}","messagePattern":"decisionTableReferenceKey expression resolves to an empty value: (.+?)","errorType":"validation","errorClass":"FlowableIllegalArgumentException","httpStatus":null,"severity":"error","filePath":"modules/flowable-engine/src/main/java/org/flowable/engine/impl/bpmn/behavior/DmnActivityBehavior.java","lineNumber":94,"sourceCode":"        ExpressionManager expressionManager = processEngineConfiguration.getExpressionManager();\r\n\r\n        if (processEngineConfiguration.isEnableProcessDefinitionInfoCache()) {\r\n            ObjectNode taskElementProperties = BpmnOverrideContext.getBpmnOverrideElementProperties(task.getId(), execution.getProcessDefinitionId());\r\n            activeDecisionKey = DynamicPropertyUtil.getActiveValue(activeDecisionKey, DynamicBpmnConstants.DMN_TASK_DECISION_TABLE_KEY, taskElementProperties);\r\n        }\r\n\r\n        String finalDecisionKeyValue = null;\r\n        Object decisionKeyValue = expressionManager.createExpression(activeDecisionKey).getValue(execution);\r\n        if (decisionKeyValue != null) {\r\n            if (decisionKeyValue instanceof String) {\r\n                finalDecisionKeyValue = (String) decisionKeyValue;\r\n            } else {\r\n                throw new FlowableIllegalArgumentException(\"decisionTableReferenceKey expression does not resolve to a string: \" + decisionKeyValue);\r\n            }\r\n        }\r\n\r\n        if (finalDecisionKeyValue == null || finalDecisionKeyValue.length() == 0) {\r\n            throw new FlowableIllegalArgumentException(\"decisionTableReferenceKey expression resolves to an empty value: \" + decisionKeyValue);\r\n        }\r\n\r\n        DmnDecisionService ruleService = CommandContextUtil.getDmnRuleService();\r\n\r\n        ExecuteDecisionBuilder executeDecisionBuilder = ruleService.createExecuteDecisionBuilder()\r\n            .decisionKey(finalDecisionKeyValue)\r\n            .instanceId(execution.getProcessInstanceId())\r\n            .executionId(execution.getId())\r\n            .activityId(task.getId())\r\n            .variables(execution.getVariables())\r\n            .tenantId(execution.getTenantId());\r\n\r\n        applyFallbackToDefaultTenant(execution, executeDecisionBuilder);\r\n        applyParentDeployment(execution, executeDecisionBuilder, processEngineConfiguration);\r\n\r\n        DecisionExecutionAuditContainer decisionExecutionAuditContainer = executeDecisionBuilder.executeWithAuditTrail();\r\n\r\n        if (decisionExecutionAuditContainer.isFailed()) {\r","sourceCodeStart":76,"sourceCodeEnd":112,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable-engine/src/main/java/org/flowable/engine/impl/bpmn/behavior/DmnActivityBehavior.java#L76-L112","documentation":"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.","triggerScenarios":"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}).","commonSituations":"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.","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"],"exampleFix":"// before\nMap<String, Object> vars = new HashMap<>(); // decisionKeyVar never set\nruntimeService.startProcessInstanceByKey(\"myProcess\", vars);\n// after\nMap<String, Object> vars = new HashMap<>();\nvars.put(\"decisionKeyVar\", \"myDecisionTable\");\nruntimeService.startProcessInstanceByKey(\"myProcess\", vars);","handlingStrategy":"validation","validationCode":"Object key = execution.getVariable(\"decisionKeyVar\");\nif (key == null || key.toString().isEmpty()) {\n    throw new IllegalStateException(\"Decision key variable must be set and non-empty before the DMN task\");\n}","typeGuard":"static boolean isPresent(String s) { return s != null && !s.isEmpty(); }","tryCatchPattern":"try {\n    runtimeService.startProcessInstanceByKey(\"myProcess\", vars);\n} catch (FlowableIllegalArgumentException e) {\n    if (e.getMessage().contains(\"resolves to an empty value\")) {\n        // restart with explicit decision key variable\n    } else throw e;\n}","preventionTips":["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"],"tags":["flowable","dmn","expression","null-value","process-variables"],"backgroundTag":"empty-required-field","analyzedSha":"d6d39ce1c69ff244f2d9dc6af756a9b95e865586","analyzedAt":"2026-09-11T06:41:19.413Z","contentChangedAt":"2026-09-11T06:41:19.413Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}