languagetool-org/languagetool · error · RuntimeException

Unexpected reference to capturing group in rule with id %s.

Error message

Unexpected reference to capturing group in rule with id %s.

What it means

Raised while a regex-based XML rule matches: the rule's message or suggestion text references a capturing group (a back-reference like \1) that the rule's regular expression never captured. The faulty input is the rule's <message>/<suggestion> markup referencing a group number that does not exist in the pattern.

Source

Thrown at languagetool-core/src/main/java/org/languagetool/rules/patterns/RegexPatternRule.java:124

        String processedSuggestionsOutMsg = processMessage(patternMatcher, suggestionsOutMsg, backReferencesInSuggestionsOutMsg,
                suggestionsInSuggestionsOutMsg, getSuggestionMatchesOutMsg());

        boolean startsWithUpperCase = patternMatcher.start() == 0 && Character.isUpperCase(text.charAt(patternMatcher.start()));
        RuleMatch ruleMatch = new RuleMatch(this, sentenceObj, markStart, markEnd, patternMatcher.start(), patternMatcher.end(),
                processedMessage, shortMessage, startsWithUpperCase, false, processedSuggestionsOutMsg, true);
        if (regexFilter != null) {
          RegexRuleFilterEvaluator ruleFilterEvaluator = new RegexRuleFilterEvaluator(regexFilter);
          RuleMatch filteredMatch = ruleFilterEvaluator.runFilter(getFilterArguments(), ruleMatch, sentenceObj, patternMatcher);
          if (filteredMatch != null) {
            matches.add(ruleMatch);
          }
        } else {
          matches.add(ruleMatch);
        }

        startPos = patternMatcher.end();
      } catch (IndexOutOfBoundsException e){
        throw new RuntimeException(String.format("Unexpected reference to capturing group in rule with id %s.", this.getFullId()), e);
      } catch (Exception e) {
        throw new RuntimeException(String.format("Unexpected exception when processing regexp in rule with id %s.", this.getFullId()), e);
      }
    }
    return matches.toArray(RuleMatch.EMPTY_ARRAY);
  }

  @NotNull
  private List<Pair<Integer, Integer>> getClausePositionsInMessage(Pattern pattern, String message) {
    Matcher matcher = pattern.matcher(message);
    List<Pair<Integer, Integer>> clausePositionsInMessage = new ArrayList<>();
    while (matcher.find()) {
      clausePositionsInMessage.add(Pair.of(matcher.start(), matcher.end()));
    }
    return clausePositionsInMessage;
  }

  private String processMessage(Matcher matcher, String message, List<Pair<Integer, Integer>> backReferences,

View on GitHub (pinned to 2e990059ce)

Solutions

  1. Add the missing capturing parentheses to the rule's regular expression so the referenced group exists
  2. Correct the back-reference number in the message so it points to an existing group
  3. Refer to the rule id quoted in the exception to locate and fix the offending grammar.xml entry
Defensive patterns

Strategy: validation

When it happens

Trigger: Thrown at languagetool-core/src/main/java/org/languagetool/rules/patterns/RegexPatternRule.java:124 when the library encounters an invalid state.

Common situations: See trigger scenarios.


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