languagetool-org/languagetool · error · RuntimeException
Got " + matcher.groupCount() + " groups for regex '" + patte
Error message
Got " + matcher.groupCount() + " groups for regex '" + pattern.pattern() + "', expected 1
What it means
PartialPosTagFilter expects its 'regexp' to contain exactly one capturing group (the part of the token to keep), unless two_groups_regexp is set. This RuntimeException is thrown when the compiled regex's groupCount() != 1 while two_groups_regexp is false.
Source
Thrown at languagetool-core/src/main/java/org/languagetool/rules/PartialPosTagFilter.java:81
boolean two_groups_regexp = args.containsKey("two_groups_regexp");
String prefix = "";
String suffix = "";
if (args.containsKey("prefix")) {
prefix = args.get("prefix");
};
if (args.containsKey("suffix")) {
suffix = args.get("suffix");
};
String token = prefix + patternTokens[tokenPos - 1].getToken() + suffix;
Matcher matcher = pattern.matcher(token);
if ((matcher.groupCount() != 1) && !(two_groups_regexp)) {
throw new RuntimeException("Got " + matcher.groupCount() + " groups for regex '" + pattern.pattern() + "', expected 1");
}
if ((matcher.groupCount() != 2) && (two_groups_regexp)) {
throw new RuntimeException("Got " + matcher.groupCount() + " groups for regex '" + pattern.pattern() + "', expected 2");
}
if (matcher.matches()) {
String partialToken = matcher.group(1);
if (matcher.groupCount() == 2) {
partialToken += matcher.group(2);
}
List<AnalyzedTokenReadings> tags = tag(partialToken);
if (tags != null && partialTagHasRequiredTag(tags, requiredTagRegexp, negatePos)) {
return match;
}
return null;
}
return null;
}
View on GitHub (pinned to 2e990059ce)
Solutions
- Wrap the part of the regex you want kept in exactly one capturing group: e.g. '(.*)ing'.
- If you truly need two capture groups, add the two_groups_regexp arg to the filter.
- Test the regex offline (Pattern.compile(...).matcher(...).groupCount()) before putting it in the rule.
Example fix
<!-- before --> <filter class="...PartialPosTagFilter" args="no:1 regexp:.*ing postag_regexp:VBZ"/> <!-- after --> <filter class="...PartialPosTagFilter" args="no:1 regexp:(.*)ing postag_regexp:VBZ"/>
Defensive patterns
Strategy: validation
Validate before calling
int groups = java.util.regex.Pattern.compile(regexp).matcher("").pattern().matcher("").groupCount(); // count via compiled pattern
int groupCount = java.util.regex.Pattern.compile(regexp).matcher("").groupCount() >= 0
? java.util.regex.Pattern.compile("(x)?").groupCount() // placeholder
: 0;
// simpler check:
java.util.regex.Pattern p = java.util.regex.Pattern.compile(regexp);
if (p.matcher("").groupCount() != 1) throw new IllegalArgumentException("regexp needs exactly 1 capturing group"); Try / catch
try {
return filter.acceptRuleMatch(match, args, pos, tokens, tokenPositions);
} catch (RuntimeException e) {
throw new RuleFormatException("Bad PartialPosTagFilter regexp: " + e.getMessage(), e);
} Prevention
- Always parenthesize the captured stem: (.*)
- Use (?:...) for non-capturing parts to keep group count at 1
- Test groupCount() in a scratch program before adding the rule
When it happens
Trigger: Setting filter arg regexp to a pattern with zero groups (e.g. 'ing' or '(?:.*)ing' with a non-capturing group) or more than two groups, without enabling two_groups_regexp.
Common situations: Writing a regex without parentheses around the captured stem, using (?:...) thinking it captures, or building the regex dynamically and miscounting groups.
Related errors
- Got " + matcher.groupCount() + " groups for regex '" + patte
- suppressMisspelledMatch must be a valid regex
- suppressMisspelledSuggestions must be a valid regex
- Format error in file ${path}, line: ${line}
- No IssueType found for name '" + name + "'. Valid values: "
AI-assisted analysis of languagetool-org/languagetool@2e990059ce (2026-09-06).
Data as JSON: /api/errors/b7a5c7020535ba46.
Report an issue: GitHub.