languagetool-org/languagetool · error · RuntimeException
Your reference number ${refNumber} is bigger than the number
Error message
Your reference number ${refNumber} is bigger than the number of tokens: ${tokenPositions.size()} What it means
In RuleFilterEvaluator.getResolvedArguments, an argument value like \N is a back-reference to the Nth pattern token. If N is larger than the number of collected token positions (or, in the following check, beyond the matched patternTokens), a RuntimeException is thrown. It means the filter references a token that does not exist in the pattern.
Source
Thrown at languagetool-core/src/main/java/org/languagetool/rules/patterns/RuleFilterEvaluator.java:65
}
/**
* Resolves the backref arguments, e.g. replaces {@code \1} by the value of the first token in the pattern.
*/
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 numberView on GitHub (pinned to 2e990059ce)
Solutions
- Lower the reference number so it points at an existing token: with N tokens, reference \1..\N (1-based).
- Recount the tokens in the <pattern> after recent edits and update every \N filter argument accordingly.
- Remember skip tokens and markers shift positions — verify against the actual matched token positions, not raw pattern text.
- Reproduce with a small test rule and print tokenPositions.size() to confirm how many positions the pattern actually yields.
Example fix
<!-- before: pattern has 2 tokens, filter references token 3 --> <filter class="..." args="no:\3"/> <!-- after --> <filter class="..." args="no:\2"/>
Defensive patterns
Strategy: validation
Validate before calling
int maxRef = 0;
for (String arg : filterArgs.split("\\s+")) {
String val = arg.substring(arg.indexOf(':') + 1);
if (val.startsWith("\\")) {
maxRef = Math.max(maxRef, Integer.parseInt(val.substring(1)));
}
}
if (maxRef > tokenPositions.size()) {
throw new IllegalArgumentException("Reference \\" + maxRef + " exceeds " + tokenPositions.size() + " tokens");
} Try / catch
try {
Map<String,String> resolved = evaluator.getResolvedArguments(filterArgs, patternTokens, pos, tokenPositions);
} catch (RuntimeException e) {
if (e.getMessage().contains("is bigger than")) {
throw new IllegalArgumentException("Back-reference out of range in: " + filterArgs, e);
}
throw e;
} Prevention
- Recount every back-reference after editing the pattern's token list or skip settings.
- Remember references are 1-based and skip handling shifts effective positions.
- Test each rule with the LanguageTools rule test framework so out-of-range references surface in CI.
- Keep the filter args line directly below the pattern it indexes for easy counting.
When it happens
Trigger: A filter argument value starting with a backslash (e.g. \3) whose number exceeds tokenPositions.size() (the number of referenced token positions in the pattern), or whose skip-corrected index is >= patternTokens.length after skip handling.
Common situations: Rule pattern edited to have fewer tokens while the filter argument still references an old higher token index; numbering tokens from 0 instead of LanguageTool's 1-based convention; off-by-one after adding/removing a skip marker; copying a filter line between rules with different pattern lengths.
Related errors
- Filter class '${className}' must implement interface ${RuleF
- Invalid syntax for key/value, expected 'key:value', got: '${
- Could not create filter class using constructor ${constructo
- Could not find filter class: '${className}' - make sure to u
- WrongParameterNumberException
AI-assisted analysis of languagetool-org/languagetool@2e990059ce (2026-09-06).
Data as JSON: /api/errors/e522c9b0ea0bff47.
Report an issue: GitHub.