languagetool-org/languagetool · error · RuntimeException
Rule group
Error message
Rule group
What it means
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.
Source
Thrown at languagetool-core/src/main/java/org/languagetool/rules/patterns/PatternRuleHandler.java:179
inRegex = true;
regexMode = "exact".equals(attrs.getValue("type")) ? RegexpMode.EXACT : RegexpMode.SMART;
regexCaseSensitive = attrs.getValue(CASE_SENSITIVE) != null && YES.equals(attrs.getValue(CASE_SENSITIVE));
regexpMark = attrs.getValue(MARK) != null ? Integer.parseInt(attrs.getValue(MARK)) : 0;
break;
case RULE:
xmlLineNumber = pLocator.getLineNumber();
regex = new StringBuilder();
inRule = true;
shortMessage = new StringBuilder();
message = new StringBuilder();
suggestionsOutMsg = new StringBuilder();
url = new StringBuilder();
id = attrs.getValue(ID);
name = attrs.getValue(NAME);
String minPrevMatchesStr = attrs.getValue(MINPREVMATCHES);
if (minPrevMatchesStr != null) {
if (inRuleGroup && ruleGroupMinPrevMatches > 0) {
throw new RuntimeException("Rule group " + ruleGroupId + " has " + MINPREVMATCHES + "=" + ruleGroupMinPrevMatches
+ ", thus rule " + id + " cannot specify " + MINPREVMATCHES);
}
minPrevMatches = Integer.parseInt(minPrevMatchesStr);
} else {
minPrevMatches = ruleGroupMinPrevMatches;
}
String distanceTokensStr = attrs.getValue(DISTANCETOKENS);
if (distanceTokensStr != null) {
if (inRuleGroup && ruleGroupDistanceTokens > 0) {
throw new RuntimeException("Rule group " + ruleGroupId + " has " + DISTANCETOKENS + "=" + ruleGroupDistanceTokens
+ ", thus rule " + id + " cannot specify " + DISTANCETOKENS);
}
distanceTokens = Integer.parseInt(distanceTokensStr);
} else {
distanceTokens = ruleGroupDistanceTokens;
}
String premiumRule = attrs.getValue(PREMIUM);
//check if this rule is premiumView on GitHub (pinned to 2e990059ce)
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
Example fix
// before <rulegroup id="G" minPrevMatches="2"> <rule id="R1" minPrevMatches="1">... // after <rulegroup id="G" minPrevMatches="2"> <rule id="R1">...
Defensive patterns
Strategy: validation
Validate before calling
if (ruleGroupMinPrevMatches > 0 && rule.hasAttribute("minPrevMatches")) {
throw new IllegalArgumentException("minPrevMatches set on both rulegroup and rule");
} Try / catch
try {
rules = handler.getRules(stream, filename);
} catch (RuntimeException e) {
if (e.getMessage().contains(MINPREVMATCHES)) {
log.error("Remove duplicate minPrevMatches in rule XML: {}", e.getMessage());
}
throw e;
} Prevention
- 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
When it happens
Trigger: Parsing pattern rule XML where <rulegroup minPrevMatches="2"> contains a <rule minPrevMatches="..."> — i.e. the attribute is specified at both levels.
Common situations: 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.
Related errors
- ApostropheTypeFilter: Index out of bounds in
- Translation language (
- No rules are active. Please make sure your rule ids (<option
- List of language models is empty
- Set 'no', 'regexp' and 'postag_regexp' for filter PartialPos
AI-assisted analysis of languagetool-org/languagetool@2e990059ce (2026-09-06).
Data as JSON: /api/errors/2cd1183759efad05.
Report an issue: GitHub.