flowable/flowable-engine · error · IllegalArgumentException

decision table does not contain a hit policy

Error message

decision table does not contain a hit policy

What it means

Every decision table processed by initializeDecisionExecutionAudit must declare a hit policy; a table with a null hit policy cannot be audited or executed deterministically, so this IllegalArgumentException is thrown after logging.

Solutions

  1. Add an explicit hitPolicy attribute to the decision table in the DMN XML (e.g. hitPolicy="UNIQUE")
  2. Set hit policy programmatically if building the model in code
  3. Re-export/re-save the DMN file from the modeling tool ensuring hit policy is set

Example fix

// before
<decisionTable> <!-- no hitPolicy -->
// after
<decisionTable hitPolicy="UNIQUE">
Defensive patterns

Strategy: validation

Validate before calling

DecisionTable dt = (DecisionTable) decision.getExpression();
if (dt.getHitPolicy() == null) throw new IllegalArgumentException("decision table must declare a hitPolicy");

Prevention

When it happens

Trigger: initializeDecisionExecutionAudit reads decision.getExpression() as a DecisionTable and finds decisionTable.getHitPolicy() == null.

Common situations: DMN XML written without the hitPolicy attribute (some editors allow omitting it; the spec default UNIQUE is not auto-applied here); hand-crafted DecisionTable models in tests; older DMN files from tools that omit hitPolicy.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


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

Appendix: source

Thrown at modules/flowable-dmn-engine/src/main/java/org/flowable/dmn/engine/impl/audit/DecisionExecutionAuditUtil.java:58

        
        DmnEngineConfiguration dmnEngineConfiguration = CommandContextUtil.getDmnEngineConfiguration();

        return new DecisionServiceExecutionAuditContainer(decisionService.getId(), decisionService.getName(), executeDecisionInfo.getDecisionVersion(),
                dmnEngineConfiguration.isStrictMode(), executeDecisionInfo.getVariables(), dmnEngineConfiguration.getClock().getCurrentTime());
    }

    public static DecisionExecutionAuditContainer initializeDecisionExecutionAudit(Decision decision, ExecuteDecisionContext executeDecisionInfo) {

        if (decision == null || decision.getId() == null) {
            LOGGER.error("decision does not contain key");
            throw new IllegalArgumentException("decision does not contain decision key");
        }

        DecisionTable decisionTable = (DecisionTable) decision.getExpression();

        if (decisionTable.getHitPolicy() == null) {
            LOGGER.error("decision table does not contain a hit policy");
            throw new IllegalArgumentException("decision table does not contain a hit policy");
        }
        
        Clock clock = CommandContextUtil.getDmnEngineConfiguration().getClock();

        return new DecisionExecutionAuditContainer(decision.getId(), decision.getName(), executeDecisionInfo.getDecisionVersion(), 
                        decisionTable.getHitPolicy(), CommandContextUtil.getDmnEngineConfiguration().isStrictMode(), 
                        executeDecisionInfo.getVariables(), clock.getCurrentTime());
    }
}

View on GitHub (pinned to d6d39ce1c6)