{"record":{"id":"8f3017553a4f8b7f","repo":"flowable/flowable-engine","slug":"hitpolicy-s-violated","errorCode":null,"errorMessage":"HitPolicy %s violated.","messagePattern":"HitPolicy (.+?) violated\\.","errorType":"exception","errorClass":"FlowableException","httpStatus":null,"severity":"error","filePath":"modules/flowable-dmn-engine/src/main/java/org/flowable/dmn/engine/impl/hitpolicy/HitPolicyAny.java","lineNumber":56,"sourceCode":"\n        for (Map.Entry<Integer, Map<String, Object>> ruleResults : executionContext.getRuleResults().entrySet()) {\n\n            for (Map.Entry<Integer, Map<String, Object>> otherRuleResults : executionContext.getRuleResults().entrySet()) {\n\n                if (!otherRuleResults.getKey().equals(ruleResults.getKey())) {\n\n                    for (Map.Entry<String, Object> outputValues : otherRuleResults.getValue().entrySet()) {\n                        if (!ruleResults.getValue().containsKey(outputValues.getKey()) ||\n                            (ruleResults.getValue().containsKey(outputValues.getKey()) && !outputValues.getValue().equals(ruleResults.getValue().get(outputValues.getKey())))) {\n\n                            String hitPolicyViolatedMessage = String.format(\"HitPolicy %s violated; both rule %d and %d are valid but output %s has different values.\",\n                                getHitPolicyName(), otherRuleResults.getKey(), ruleResults.getKey(), outputValues.getKey());\n\n                            if (CommandContextUtil.getDmnEngineConfiguration().isStrictMode()) {\n                                executionContext.getAuditContainer().getRuleExecutions().get(otherRuleResults.getKey()).setExceptionMessage(hitPolicyViolatedMessage);\n                                executionContext.getAuditContainer().getRuleExecutions().get(ruleResults.getKey()).setExceptionMessage(hitPolicyViolatedMessage);\n\n                                throw new FlowableException(String.format(\"HitPolicy %s violated.\", getHitPolicyName()));\n                            } else {\n                                validationFailed = true;\n\n                                executionContext.getAuditContainer().getRuleExecutions().get(otherRuleResults.getKey()).setValidationMessage(hitPolicyViolatedMessage);\n                                executionContext.getAuditContainer().getRuleExecutions().get(ruleResults.getKey()).setValidationMessage(hitPolicyViolatedMessage);\n\n                                break;\n                            }\n                        }\n                    }\n                }\n            }\n        }\n\n        List<Map<String, Object>> ruleResults = new ArrayList<>(executionContext.getRuleResults().values());\n        if (!ruleResults.isEmpty()) {\n            if (CommandContextUtil.getDmnEngineConfiguration().isStrictMode() == false && validationFailed) {\n                executionContext.getAuditContainer().setValidationMessage(String.format(\"HitPolicy %s violated; multiple valid rules with different outcomes. Setting last valid rule result as final result.\", getHitPolicyName()));","sourceCodeStart":38,"sourceCodeEnd":74,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable-dmn-engine/src/main/java/org/flowable/dmn/engine/impl/hitpolicy/HitPolicyAny.java#L38-L74","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Adjust rule conditions so at most one rule can match (tighten conditions or add priority)","Change the hit policy from ANY to FIRST if the first matching rule should win","Inspect the audit/rule execution messages identifying the conflicting rule numbers and fix those rows","Enable/align strictMode intentionally: keep strict mode to fail fast in tests, disable for lenient validation-only behavior"],"exampleFix":"// before (two overlapping rules under hit policy ANY)\n<hitPolicy>ANY</hitPolicy>  <!-- rule 1: age > 18; rule 2: age > 21 -->\n// after (make rules mutually exclusive)\n<!-- rule 1: age > 18 && age <= 21; rule 2: age > 21 -->","handlingStrategy":"validation","validationCode":"// pre-check: simulate table with input to ensure at most one ANY-rule matches\nassert countMatchingRules(table, input) <= 1 : \"ANY hit policy would be violated\";","typeGuard":null,"tryCatchPattern":"try { decisionTable.execute(input); } catch (FlowableException e) { if (e.getMessage().startsWith(\"HitPolicy\")) { /* fix overlapping rules */ } throw e; }","preventionTips":["Design ANY-policy rules to be mutually exclusive","Prefer FIRST policy when overlap is possible","Test decision tables with boundary inputs before deployment"],"tags":["dmn","hit-policy","decision-table","validation"],"backgroundTag":"schema-validation-failed","analyzedSha":"d6d39ce1c69ff244f2d9dc6af756a9b95e865586","analyzedAt":"2026-09-11T06:41:19.413Z","contentChangedAt":"2026-09-11T06:41:19.413Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}