flowable/flowable-engine · error · FlowableException

DMN decision with key ${finalDecisionKeyValue} did not hit a

Error message

DMN decision with key ${finalDecisionKeyValue} did not hit any rules for the provided input. In ${execution}

What it means

The decision executed successfully but no rule matched the provided input, and the task's 'decisionTableThrowErrorOnNoHit' flag field (EXPRESSION_DECISION_TABLE_THROW_ERROR_FLAG) was set so that this condition must fail the task. Flowable throws this FlowableException when the flag is the literal 'true'; if the flag is an expression, it throws only when that expression evaluates to Boolean true. It signals incomplete decision coverage rather than an engine malfunction.

Source

Thrown at modules/flowable-engine/src/main/java/org/flowable/engine/impl/bpmn/behavior/DmnActivityBehavior.java:130

        if (decisionExecutionAuditContainer.isFailed()) {
            throw new FlowableException("DMN decision with key " + finalDecisionKeyValue + " execution failed in " + execution,
                    decisionExecutionAuditContainer.getException());
        }

        /*Throw error if there were no rules hit when the flag indicates to do this.*/
        FieldExtension throwErrorFieldExtension = DelegateHelper.getFlowElementField(execution, EXPRESSION_DECISION_TABLE_THROW_ERROR_FLAG);
        if (throwErrorFieldExtension != null) {
            String throwErrorString = null;
            if (StringUtils.isNotEmpty(throwErrorFieldExtension.getStringValue())) {
                throwErrorString = throwErrorFieldExtension.getStringValue();
                
            } else if (StringUtils.isNotEmpty(throwErrorFieldExtension.getExpression())) {
                throwErrorString = throwErrorFieldExtension.getExpression();
            }
            
            if (decisionExecutionAuditContainer.getDecisionResult().isEmpty() && throwErrorString != null) {
                if ("true".equalsIgnoreCase(throwErrorString)) {
                    throw new FlowableException("DMN decision with key " + finalDecisionKeyValue + " did not hit any rules for the provided input. In " + execution);
                    
                } else if (!"false".equalsIgnoreCase(throwErrorString)) {
                    Expression expression = expressionManager.createExpression(throwErrorString);
                    Object expressionValue = expression.getValue(execution);
                    
                    if (expressionValue instanceof Boolean && ((Boolean) expressionValue)) {
                        throw new FlowableException("DMN decision with key " + finalDecisionKeyValue + " did not hit any rules for the provided input. In " + execution);
                    }
                }
            }
        }

        if (processEngineConfiguration.getDecisionTableVariableManager() != null) {
            if (decisionExecutionAuditContainer instanceof DecisionServiceExecutionAuditContainer decisionServiceExecutionAuditContainer) {
                processEngineConfiguration.getDecisionTableVariableManager().setDecisionServiceVariablesOnExecution(decisionServiceExecutionAuditContainer.getDecisionServiceResult(),
                    finalDecisionKeyValue, execution, processEngineConfiguration.getObjectMapper(), decisionExecutionAuditContainer.isMultipleResults());
            } else {
                processEngineConfiguration.getDecisionTableVariableManager().setVariablesOnExecution(decisionExecutionAuditContainer.getDecisionResult(),

View on GitHub (pinned to d6d39ce1c6)

Solutions

  1. Add a catch-all/default rule to the decision table covering unmatched inputs
  2. Set the throw-error field to "false" (or remove it) if no-hit should be tolerated and handled by checking the empty result instead
  3. Fix or validate the input variables before the DMN task so they fall inside existing rule conditions
  4. Keep the flag but wrap the DMN task in a boundary error event in the process model to handle no-hit outcomes gracefully

Example fix

// before (BPMN XML)
<flowable:field name="decisionTableThrowErrorOnNoHit" stringValue="true" />
// after
<flowable:field name="decisionTableThrowErrorOnNoHit" stringValue="false" /> // or add a default rule to the DMN table
Defensive patterns

Strategy: validation

Validate before calling

DecisionExecutionAuditContainer audit = executeDecisionBuilder.executeWithAuditTrail();
if (audit.getDecisionResult() == null || audit.getDecisionResult().isEmpty()) {
    log.warn("No DMN rule hit for inputs {}", inputVars);
}

Try / catch

try {
    taskService.complete(taskId);
} catch (FlowableException e) {
    if (e.getMessage().contains("did not hit any rules")) {
        // handle no-hit business case explicitly
    } else throw e;
}

Prevention

When it happens

Trigger: decisionExecutionAuditContainer.getDecisionResult().isEmpty() (zero rules hit) AND the throwError field extension resolves to "true" or to an expression evaluating to true; typically input data doesn't satisfy any rule's conditions while strict no-hit enforcement is configured.

Common situations: Incomplete rule coverage in the decision table (no default/fallback rule); input values outside the ranges covered by rules; caller passes unexpected/edge-case data (null age, unknown category); deliberate strict mode where any no-hit must fail the process.

Understand the failure class

Background: EmptyResultError / "no results found": when an API or scraper succeeds but returns zero rows — this error's family across 9 libraries.

Related errors


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