{"record":{"id":"2cd1183759efad05","repo":"languagetool-org/languagetool","slug":"rule-group","errorCode":null,"errorMessage":"Rule group ","messagePattern":"Rule group ","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"languagetool-core/src/main/java/org/languagetool/rules/patterns/PatternRuleHandler.java","lineNumber":179,"sourceCode":"        inRegex = true;\n        regexMode = \"exact\".equals(attrs.getValue(\"type\")) ? RegexpMode.EXACT : RegexpMode.SMART;\n        regexCaseSensitive = attrs.getValue(CASE_SENSITIVE) != null && YES.equals(attrs.getValue(CASE_SENSITIVE));\n        regexpMark = attrs.getValue(MARK) != null ? Integer.parseInt(attrs.getValue(MARK)) : 0;\n        break;\n      case RULE:\n        xmlLineNumber = pLocator.getLineNumber();\n        regex = new StringBuilder();\n        inRule = true;\n        shortMessage = new StringBuilder();\n        message = new StringBuilder();\n        suggestionsOutMsg = new StringBuilder();\n        url = new StringBuilder();\n        id = attrs.getValue(ID);\n        name = attrs.getValue(NAME);\n        String minPrevMatchesStr = attrs.getValue(MINPREVMATCHES);\n        if (minPrevMatchesStr != null) {\n          if (inRuleGroup && ruleGroupMinPrevMatches > 0) {\n            throw new RuntimeException(\"Rule group \" + ruleGroupId + \" has \" + MINPREVMATCHES + \"=\" + ruleGroupMinPrevMatches\n                + \", thus rule \" + id + \" cannot specify \" + MINPREVMATCHES);\n          }\n          minPrevMatches = Integer.parseInt(minPrevMatchesStr);  \n        } else {\n          minPrevMatches = ruleGroupMinPrevMatches;\n        }\n        String distanceTokensStr = attrs.getValue(DISTANCETOKENS);\n        if (distanceTokensStr != null) {\n          if (inRuleGroup && ruleGroupDistanceTokens > 0) {\n            throw new RuntimeException(\"Rule group \" + ruleGroupId + \" has \" + DISTANCETOKENS + \"=\" + ruleGroupDistanceTokens\n                + \", thus rule \" + id + \" cannot specify \" + DISTANCETOKENS);\n          }\n          distanceTokens = Integer.parseInt(distanceTokensStr);  \n        } else {\n          distanceTokens = ruleGroupDistanceTokens;\n        }\n        String premiumRule = attrs.getValue(PREMIUM);\n        //check if this rule is premium","sourceCodeStart":161,"sourceCodeEnd":197,"githubUrl":"https://github.com/languagetool-org/languagetool/blob/2e990059ce67d5e2a0f7f7ca5d31160c6709df4b/languagetool-core/src/main/java/org/languagetool/rules/patterns/PatternRuleHandler.java#L161-L197","documentation":"In pattern-rule XML, minPrevMatches may be set on a <rulegroup> or on individual <rule> elements, not both in a conflicting way. If a rule declares minPrevMatches while its rule group already set it to a value > 0, PatternRuleHandler.startElement throws this RuntimeException to prevent ambiguous inheritance.","triggerScenarios":"Parsing pattern rule XML where <rulegroup minPrevMatches=\"2\"> contains a <rule minPrevMatches=\"...\"> — i.e. the attribute is specified at both levels.","commonSituations":"Merging rule XML files or copying rules between groups, moving minPrevMatches to the group but leaving it on child rules (or vice versa), and bulk edits that duplicate the attribute.","solutions":["Remove the minPrevMatches attribute from the inner <rule> and rely on the rulegroup value","Or remove it from the <rulegroup> if the per-rule values are intended to differ","Search the XML for rules inside groups that both define minPrevMatches and resolve the duplication"],"exampleFix":"// before\n<rulegroup id=\"G\" minPrevMatches=\"2\">\n  <rule id=\"R1\" minPrevMatches=\"1\">...\n// after\n<rulegroup id=\"G\" minPrevMatches=\"2\">\n  <rule id=\"R1\">...","handlingStrategy":"validation","validationCode":"if (ruleGroupMinPrevMatches > 0 && rule.hasAttribute(\"minPrevMatches\")) {\n  throw new IllegalArgumentException(\"minPrevMatches set on both rulegroup and rule\");\n}","typeGuard":null,"tryCatchPattern":"try {\n  rules = handler.getRules(stream, filename);\n} catch (RuntimeException e) {\n  if (e.getMessage().contains(MINPREVMATCHES)) {\n    log.error(\"Remove duplicate minPrevMatches in rule XML: {}\", e.getMessage());\n  }\n  throw e;\n}","preventionTips":["Define minPrevMatches at exactly one level (group or rule)","Grep rule XML for nested minPrevMatches attributes in CI","Document group-level inheritance when authoring rules"],"tags":["rule-xml","pattern-rule","conflicting-attributes","configuration"],"backgroundTag":"conflicting-config-options","analyzedSha":"2e990059ce67d5e2a0f7f7ca5d31160c6709df4b","analyzedAt":"2026-09-06T09:20:17.015Z","contentChangedAt":"2026-09-06T09:20:17.015Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}