languagetool-org/languagetool · error · RuntimeException

Your reference number ${refNumber} is bigger than number of

Error message

Your reference number ${refNumber} is bigger than number of matching tokens: ${patternTokens.length}

What it means

Thrown by LanguageTool's RuleFilterEvaluator when a rule filter argument references a matched token by number (e.g. '1') and that skip-corrected index is beyond the tokens that actually matched the pattern. In LanguageTool rule XML, filters receive resolved arguments built from back-references into the matched sentence; this check prevents an ArrayIndexOutOfBoundsException when the reference exceeds patternTokens.length after skip correction. It indicates the rule's filter attribute points at a token position that does not exist in the current match.

Source

Thrown at languagetool-core/src/main/java/org/languagetool/rules/patterns/RuleFilterEvaluator.java:69

   */
  public Map<String,String> getResolvedArguments(String filterArgs, AnalyzedTokenReadings[] patternTokens, int patternTokenPos, List<Integer> tokenPositions) {
    Map<String,String> result = new HashMap<>();
    String[] arguments = WHITESPACE.split(filterArgs);
    for (String arg : arguments) {
      int delimPos = arg.indexOf(':');
      if (delimPos == -1) {
        throw new RuntimeException("Invalid syntax for key/value, expected 'key:value', got: '" + arg + "'");
      }
      String key = arg.substring(0, delimPos);
      String val = arg.substring(delimPos + 1);
      if (val.startsWith("\\")) {
        int refNumber = Integer.parseInt(val.replace("\\", ""));
        if (refNumber > tokenPositions.size()) {
          throw new RuntimeException("Your reference number " + refNumber + " is bigger than the number of tokens: " + tokenPositions.size());
        }
        int correctedRef = getSkipCorrectedReference(tokenPositions, refNumber);
        if (correctedRef >= patternTokens.length) {
          throw new RuntimeException("Your reference number " + refNumber +
                  " is bigger than number of matching tokens: " + patternTokens.length);
        }
        if (result.containsKey(key)) {
          throw new RuntimeException("Duplicate key '" + key + "'");
        }
        result.put(key, patternTokens[correctedRef].getToken());
      } else {
        result.put(key, val);
      }
    }
    return result;
  }

  // when there's a 'skip', we need to adapt the reference number
  private int getSkipCorrectedReference(List<Integer> tokenPositions, int refNumber) {
    int correctedRef = 0;
    int i = 0;
    for (int tokenPosition : tokenPositions) {

View on GitHub (pinned to 2e990059ce)

Solutions

  1. Reduce the reference number in the filter args attribute so it indexes within the number of pattern tokens
  2. Add or adjust pattern tokens/skip so that the referenced position actually exists in the match
  3. Log patternTokens.length vs refNumber (enable debug on RuleFilterEvaluator) to see how many tokens matched
  4. Wrap filter evaluation in try-catch during rule test runs to catch and report the offending rule id

Example fix

// before (rule XML)
<filter class="org.languagetool.rules.en.MyFilter" args="no:3"/>
// after (pattern has only 2 tokens, so reference token 2)
<filter class="org.languagetool.rules.en.MyFilter" args="no:2"/>
Defensive patterns

Strategy: validation

Validate before calling

// Count backward-referenced token positions in the pattern before loading
int patternTokenCount = /* number of <token>/<match> pattern tokens in the rule */;
int maxRef = parseMaxFilterRef(ruleXml); // highest 'no:N' in filter args
if (maxRef > patternTokenCount) {
  throw new IllegalStateException("Rule " + ruleId + ": filter ref " + maxRef + " exceeds " + patternTokenCount + " tokens");
}

Type guard

boolean isValidRef(int refNumber, int patternTokenCount) {
  return refNumber >= 1 && refNumber <= patternTokenCount;
}

Try / catch

try {
  evaluator.getResolvedArguments(filterId, args, matches, patternTokens);
} catch (RuntimeException e) {
  if (e.getMessage().contains("is bigger than number of matching tokens")) {
    log.error("Bad filter reference in rule; fix args", e);
  } else throw e;
}

Prevention

When it happens

Trigger: A <filter class='...' args='no:2 arg:3'/> (or similar) references token positions higher than the number of pattern tokens matched, especially when <marker>/<skip> causes fewer tokens than expected to be captured; getResolvedArguments parses each ref value and validates correctedRef < patternTokens.length.

Common situations: Authors of custom disambiguator/rule XML write filter references like 'no:3' in a two-token pattern; rules that rely on skip counting assume more matched tokens than are actually available after skip correction; rule copied from another rule with more tokens.

Related errors


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