languagetool-org/languagetool · error · RuntimeException

Got " + matcher.groupCount() + " groups for regex '" + patte

Error message

Got " + matcher.groupCount() + " groups for regex '" + pattern.pattern() + "', expected 2

What it means

Companion to error 54: when the filter arg two_groups_regexp is set, PartialPosTagFilter requires the regex to have exactly 2 capturing groups (second group appended to the partial token). This RuntimeException is thrown when groupCount() != 2 while two_groups_regexp is true.

Source

Thrown at languagetool-core/src/main/java/org/languagetool/rules/PartialPosTagFilter.java:84

      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;
  }

  private boolean partialTagHasRequiredTag(List<AnalyzedTokenReadings> tags, String requiredTagRegexp, boolean negatePos) {
    // Without negate_pos=yes: return true if any postag matches the regexp.
    // With negate_pos=yes:    return true if there are postag and none them matches the regexp.

View on GitHub (pinned to 2e990059ce)

Solutions

  1. Make the regex contain exactly two capturing groups, e.g. 'pre(.*)post(.*)'.
  2. If only one group is needed, remove the two_groups_regexp arg instead.
  3. Verify group count programmatically before deploying the rule.

Example fix

<!-- before -->
<filter class="...PartialPosTagFilter" args="no:1 two_groups_regexp regexp:(.*)ing postag_regexp:VBZ"/>
<!-- after -->
<filter class="...PartialPosTagFilter" args="no:1 two_groups_regexp regexp:(.*)(ing) postag_regexp:VBZ"/>
Defensive patterns

Strategy: validation

Validate before calling

java.util.regex.Pattern p = java.util.regex.Pattern.compile(regexp);
if (twoGroups && p.matcher("").groupCount() != 2) {
  throw new IllegalArgumentException("two_groups_regexp requires exactly 2 capturing groups");
}

Try / catch

try {
  return filter.acceptRuleMatch(match, args, pos, tokens, tokenPositions);
} catch (RuntimeException e) {
  throw new RuleFormatException("Bad two_groups_regexp pattern: " + e.getMessage(), e);
}

Prevention

When it happens

Trigger: Declaring two_groups_regexp in the filter args but supplying a regex with fewer or more than two capturing groups.

Common situations: Enabling two_groups_regexp for an infix/prefix match but leaving the regex from a single-group example; escaping mistakes that turn '(' groups into literals.

Related errors


AI-assisted analysis of languagetool-org/languagetool@2e990059ce (2026-09-06). Data as JSON: /api/errors/a41fe2435b46928c. Report an issue: GitHub.