flowable/flowable-engine · error · IllegalArgumentException

no decision provided

Error message

no decision provided

What it means

java.lang.IllegalArgumentException thrown by RuleEngineExecutorImpl.execute(Decision, ExecuteDecisionContext) when the Decision argument is null. The rule engine executor cannot evaluate anything without a decision model, so it fails fast before attempting to resolve the decision table.

Solutions

  1. Ensure the DMN decision is deployed: verify the .dmn.xml resource is included in the deployment and check dmnRepositoryService.createDeployment().deploy().
  2. Resolve the Decision with dmnRepositoryService.getDecisionById(...) or a query and null-check the result before executing.
  3. Verify the decision key/id spelling and that the correct tenant is being used in multi-tenant setups.

Example fix

// before
Decision decision = dmnRepositoryService.getDecisionById(decisionId);
ruleEngineExecutor.execute(decision, context);
// after
Decision decision = dmnRepositoryService.getDecisionById(decisionId);
if (decision == null) {
    throw new IllegalStateException("Decision not deployed: " + decisionId);
}
ruleEngineExecutor.execute(decision, context);
Defensive patterns

Strategy: validation

Validate before calling

Decision decision = dmnRepositoryService.getDecisionById(decisionId);
if (decision == null) {
    throw new IllegalStateException("Decision not found: " + decisionId);
}
ruleEngineExecutor.execute(decision, executeDecisionInfo);

Type guard

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

Try / catch

try {
    ruleEngineExecutor.execute(decision, ctx);
} catch (IllegalArgumentException e) {
    if (e.getMessage().contains("no decision")) {
        throw new IllegalStateException("Decision was not resolved/deployed before execution", e);
    }
    throw e;
}

Prevention

When it happens

Trigger: Calling ruleEngineExecutor.execute(null, context) directly, or indirectly when a decision lookup by key/id (e.g. via DmnRepositoryService) returned null and the result was passed on without checking.

Common situations: Deployment mismatch: querying for a decision by key in a tenant where it was never deployed, so getDecisionById/getDecision returns null; typo in decision key; decision not deployed yet when an async job fires.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


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

Appendix: source

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

            ObjectMapper objectMapper, DmnEngineConfiguration dmnEngineConfiguration) {
        
        this.hitPolicyBehaviors = hitPolicyBehaviors;
        this.expressionManager = expressionManager;
        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);

View on GitHub (pinned to d6d39ce1c6)