flowable/flowable-engine · error · FlowableException

HitPolicy %s violated.

Error message

HitPolicy %s violated.

What it means

HitPolicyAny.composeDecisionResults enforces DMN's ANY hit policy: at most one rule may produce output. When two rule results produce conflicting output values, strict mode throws FlowableException('HitPolicy ANY violated.'); otherwise it records validation messages on the audit container and fails validation gracefully.

Source

Thrown at modules/flowable-dmn-engine/src/main/java/org/flowable/dmn/engine/impl/hitpolicy/HitPolicyAny.java:56

        for (Map.Entry<Integer, Map<String, Object>> ruleResults : executionContext.getRuleResults().entrySet()) {

            for (Map.Entry<Integer, Map<String, Object>> otherRuleResults : executionContext.getRuleResults().entrySet()) {

                if (!otherRuleResults.getKey().equals(ruleResults.getKey())) {

                    for (Map.Entry<String, Object> outputValues : otherRuleResults.getValue().entrySet()) {
                        if (!ruleResults.getValue().containsKey(outputValues.getKey()) ||
                            (ruleResults.getValue().containsKey(outputValues.getKey()) && !outputValues.getValue().equals(ruleResults.getValue().get(outputValues.getKey())))) {

                            String hitPolicyViolatedMessage = String.format("HitPolicy %s violated; both rule %d and %d are valid but output %s has different values.",
                                getHitPolicyName(), otherRuleResults.getKey(), ruleResults.getKey(), outputValues.getKey());

                            if (CommandContextUtil.getDmnEngineConfiguration().isStrictMode()) {
                                executionContext.getAuditContainer().getRuleExecutions().get(otherRuleResults.getKey()).setExceptionMessage(hitPolicyViolatedMessage);
                                executionContext.getAuditContainer().getRuleExecutions().get(ruleResults.getKey()).setExceptionMessage(hitPolicyViolatedMessage);

                                throw new FlowableException(String.format("HitPolicy %s violated.", getHitPolicyName()));
                            } else {
                                validationFailed = true;

                                executionContext.getAuditContainer().getRuleExecutions().get(otherRuleResults.getKey()).setValidationMessage(hitPolicyViolatedMessage);
                                executionContext.getAuditContainer().getRuleExecutions().get(ruleResults.getKey()).setValidationMessage(hitPolicyViolatedMessage);

                                break;
                            }
                        }
                    }
                }
            }
        }

        List<Map<String, Object>> ruleResults = new ArrayList<>(executionContext.getRuleResults().values());
        if (!ruleResults.isEmpty()) {
            if (CommandContextUtil.getDmnEngineConfiguration().isStrictMode() == false && validationFailed) {
                executionContext.getAuditContainer().setValidationMessage(String.format("HitPolicy %s violated; multiple valid rules with different outcomes. Setting last valid rule result as final result.", getHitPolicyName()));

View on GitHub (pinned to d6d39ce1c6)

Solutions

  1. Adjust rule conditions so at most one rule can match (tighten conditions or add priority)
  2. Change the hit policy from ANY to FIRST if the first matching rule should win
  3. Inspect the audit/rule execution messages identifying the conflicting rule numbers and fix those rows
  4. Enable/align strictMode intentionally: keep strict mode to fail fast in tests, disable for lenient validation-only behavior

Example fix

// before (two overlapping rules under hit policy ANY)
<hitPolicy>ANY</hitPolicy>  <!-- rule 1: age > 18; rule 2: age > 21 -->
// after (make rules mutually exclusive)
<!-- rule 1: age > 18 && age <= 21; rule 2: age > 21 -->
Defensive patterns

Strategy: validation

Validate before calling

// pre-check: simulate table with input to ensure at most one ANY-rule matches
assert countMatchingRules(table, input) <= 1 : "ANY hit policy would be violated";

Try / catch

try { decisionTable.execute(input); } catch (FlowableException e) { if (e.getMessage().startsWith("HitPolicy")) { /* fix overlapping rules */ } throw e; }

Prevention

When it happens

Trigger: Executing a DMN decision table with hit policy ANY where two or more rules with valid matches return different output values for the same output expression.

Common situations: Overlapping rule conditions that were intended to be mutually exclusive; model edits that loosened a condition causing two rules to match; mistaken use of ANY instead of FIRST for tables that allow multiple hits.

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/8f3017553a4f8b7f. Report an issue: GitHub.