flowable/flowable-engine · error · FlowableException

no execution context available

Error message

no execution context available

What it means

evaluateDecisionTable requires a non-null ELExecutionContext to evaluate expressions and record the audit trail. When the passed context is null it throws FlowableException("no execution context available") (RuleEngineExecutorImpl.java:114-116). In the default flow execute() builds the context via ELExecutionContextBuilder.build so this only fires when build returns null (e.g. a broken custom builder) or when evaluateDecisionTable is invoked directly with a null context. Unlike the IllegalArgumentException guards, this FlowableException is caught by execute() and recorded on the audit container as a failed decision.

Source

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

            executionContext.getAuditContainer().setExceptionMessage(getExceptionMessage(fe));

        } finally {
            // end audit trail
            executionContext.getAuditContainer().stopAudit(dmnEngineConfiguration.getClock().getCurrentTime());
        }

        return executionContext.getAuditContainer();
    }

    protected void evaluateDecisionTable(DecisionTable decisionTable, ELExecutionContext executionContext) {
        if (decisionTable == null || decisionTable.getRules().isEmpty()) {
            throw new IllegalArgumentException("no rules present in table");
        }

        LOGGER.debug("Start table evaluation: {}", decisionTable.getId());

        if (executionContext == null) {
            throw new FlowableException("no execution context available");
        }

        try {
            // evaluate rule conditions
            Map<Integer, List<RuleOutputClauseContainer>> validRuleOutputEntries = new HashMap<>();

            for (DecisionRule rule : decisionTable.getRules()) {
                boolean ruleResult = executeRule(rule, executionContext);

                if (ruleResult) {
                    // evaluate decision table hit policy validity
                    if (getHitPolicyBehavior(decisionTable.getHitPolicy()) instanceof EvaluateRuleValidityBehavior) {
                        ((EvaluateRuleValidityBehavior) getHitPolicyBehavior(decisionTable.getHitPolicy())).evaluateRuleValidity(rule.getRuleNumber(), executionContext);
                    }

                    // add valid rule output(s)
                    validRuleOutputEntries.put(rule.getRuleNumber(), rule.getOutputEntries());
                }

View on GitHub (pinned to d6d39ce1c6)

Solutions

  1. Ensure ELExecutionContextBuilder.build returns a valid context — check your DmnEngineConfiguration and any custom builder overrides.
  2. In tests, construct a real ELExecutionContext (via ELExecutionContextBuilder.build(decision, executeDecisionInfo)) instead of passing/mock-returning null.
  3. If calling evaluateDecisionTable directly, always build the context first.
  4. Catch FlowableException around execute() and inspect the audit container's exceptionMessage if you want graceful failure handling.

Example fix

// before
ruleEngineExecutor.evaluateDecisionTable(table, null); // FlowableException
// after
ELExecutionContext ctx = ELExecutionContextBuilder.build(decision, executeDecisionInfo);
ruleEngineExecutor.evaluateDecisionTable(table, ctx);
Defensive patterns

Strategy: validation

Validate before calling

ELExecutionContext ctx = ELExecutionContextBuilder.build(decision, executeDecisionInfo);
if (ctx == null) {
    throw new IllegalStateException("ELExecutionContextBuilder returned null; check custom builder/engine configuration");
}

Try / catch

try {
    audit = ruleEngineExecutor.execute(decision, executeDecisionInfo);
} catch (FlowableException fe) {
    log.error("DMN execution failed: {}", fe.getMessage(), fe);
    audit = null; // or fall back
}

Prevention

When it happens

Trigger: Subclassing RuleEngineExecutorImpl / overriding ELExecutionContextBuilder so build() yields null; calling the protected evaluateDecisionTable(table, null) directly from custom code; any path where execute()'s context construction is bypassed or stubbed in tests.

Common situations: Unit tests mocking ELExecutionContextBuilder.build to return null, custom DMN engine configuration that replaces the context builder, or reflective/internal calls into evaluateDecisionTable without a proper context.

Related errors


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