flowable/flowable-engine · error · IllegalArgumentException

no decision table present in decision

Error message

no decision table present in decision

What it means

Flowable's DMN rule engine refuses to execute a Decision whose expression is either null or not a DecisionTable instance. RuleEngineExecutorImpl.execute() only supports decision-table decisions; a Decision backed by any other expression type (or an empty/incorrectly deployed decision) fails this instanceof guard at RuleEngineExecutorImpl.java:81-83. Because it is an IllegalArgumentException thrown before the try block, it propagates straight to the caller instead of being recorded in the audit container.

Solutions

  1. Verify the deployed DMN resource actually contains a <decisionTable> inside the decision (open the .dmn XML and check), then redeploy it.
  2. Check that the decision you pass to execute comes from DmnRepositoryService via createDecisionQuery / deployment, not a manually constructed Decision with no expression set.
  3. If you need non-tabular decisions, do not call this executor; use the appropriate API or add a decision table to the model.
  4. Inspect ELExecutionContextBuilder/decision conversion for your Flowable version — older DMN models may need re-export from the DMN modeler.

Example fix

// before
Decision decision = new Decision();
auditContainer = ruleEngineExecutor.execute(decision, ctx); // throws: no expression
// after
Decision decision = new Decision();
DecisionTable table = new DecisionTable();
table.setRules(rules);
decision.setExpression(table);
auditContainer = ruleEngineExecutor.execute(decision, ctx);
Defensive patterns

Strategy: validation

Validate before calling

if (decision == null || !(decision.getExpression() instanceof DecisionTable)) {
    throw new IllegalStateException("decision is not backed by a decision table; check the deployed .dmn resource");
}

Type guard

boolean isDecisionTableDecision(Decision d) {
    return d != null && d.getExpression() instanceof DecisionTable;
}

Prevention

When it happens

Trigger: Calling DmnEngine.executeDecision / RuleEngineExecutor.execute(decision, executeDecisionInfo) where decision.getExpression() returns null, or returns a non-DecisionTable expression (e.g. the decision in the deployed DMN XML is a decision defined without a decision table, or the Decision model was assembled programmatically without setting a DecisionTable expression).

Common situations: Deploying a DMN XML file whose <decision> element has no <decisionTable> child (e.g. only a literal expression), loading a Decision from a partially converted/parsed model, passing a hand-built Decision object to the executor in tests, or fetching a decision from the repository whose definition failed to convert to a decision table on an older Flowable version.

Related errors


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

Appendix: source

Thrown at modules/flowable-dmn-engine/src/main/java/org/flowable/dmn/engine/impl/RuleEngineExecutorImpl.java:82

        this.objectMapper = objectMapper;
        this.dmnEngineConfiguration = dmnEngineConfiguration;
    }

    /**
     * Executes the given decision and creates the outcome results
     *
     * @param decision            the DMN decision
     * @param executeDecisionInfo
     * @return updated execution variables map
     */
    @Override
    public DecisionExecutionAuditContainer execute(Decision decision, ExecuteDecisionContext executeDecisionInfo) {
        if (decision == null) {
            throw new IllegalArgumentException("no decision provided");
        }

        if (decision.getExpression() == null || !(decision.getExpression() instanceof DecisionTable currentDecisionTable)) {
            throw new IllegalArgumentException("no decision table present in decision");
        }

        // create execution context and audit trail
        ELExecutionContext executionContext = ELExecutionContextBuilder.build(decision, executeDecisionInfo);

        try {
            sanityCheckDecisionTable(currentDecisionTable);

            // evaluate decision table
            evaluateDecisionTable(currentDecisionTable, executionContext);

        } catch (FlowableException fe) {
            LOGGER.error("decision table execution sanity check failed", fe);
            executionContext.getAuditContainer().setFailedWithException(fe);
            executionContext.getAuditContainer().setExceptionMessage(getExceptionMessage(fe));

        } finally {
            // end audit trail

View on GitHub (pinned to d6d39ce1c6)