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
- Reduce the reference number in the filter args attribute so it indexes within the number of pattern tokens
- Add or adjust pattern tokens/skip so that the referenced position actually exists in the match
- Log patternTokens.length vs refNumber (enable debug on RuleFilterEvaluator) to see how many tokens matched
- 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
- Keep filter reference numbers within the number of pattern tokens (1-based)
- Re-count references after editing skip attributes or reordering tokens
- Run LanguageTool rule unit tests in CI for every rule change
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
- Duplicate key '${key}'
- ApostropheTypeFilter: Index out of bounds in
- RuleFilter: Index out of bounds in ${match.getRule().getFull
- References cannot be empty: Line: ${pLocator.getLineNumber
- References must be larger than 0: ${attrs.getValue("no")} L
AI-assisted analysis of languagetool-org/languagetool@2e990059ce (2026-09-06).
Data as JSON: /api/errors/596058b7462516e0.
Report an issue: GitHub.