{"record":{"id":"e522c9b0ea0bff47","repo":"languagetool-org/languagetool","slug":"your-reference-number-refnumber-is-bigger-than","errorCode":null,"errorMessage":"Your reference number ${refNumber} is bigger than the number of tokens: ${tokenPositions.size()}","messagePattern":"Your reference number (.+?) is bigger than the number of tokens: (.+?)","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"languagetool-core/src/main/java/org/languagetool/rules/patterns/RuleFilterEvaluator.java","lineNumber":65,"sourceCode":"  }\n\n  /**\n   * Resolves the backref arguments, e.g. replaces {@code \\1} by the value of the first token in the pattern.\n   */\n  public Map<String,String> getResolvedArguments(String filterArgs, AnalyzedTokenReadings[] patternTokens, int patternTokenPos, List<Integer> tokenPositions) {\n    Map<String,String> result = new HashMap<>();\n    String[] arguments = WHITESPACE.split(filterArgs);\n    for (String arg : arguments) {\n      int delimPos = arg.indexOf(':');\n      if (delimPos == -1) {\n        throw new RuntimeException(\"Invalid syntax for key/value, expected 'key:value', got: '\" + arg + \"'\");\n      }\n      String key = arg.substring(0, delimPos);\n      String val = arg.substring(delimPos + 1);\n      if (val.startsWith(\"\\\\\")) {\n        int refNumber = Integer.parseInt(val.replace(\"\\\\\", \"\"));\n        if (refNumber > tokenPositions.size()) {\n          throw new RuntimeException(\"Your reference number \" + refNumber + \" is bigger than the number of tokens: \" + tokenPositions.size());\n        }\n        int correctedRef = getSkipCorrectedReference(tokenPositions, refNumber);\n        if (correctedRef >= patternTokens.length) {\n          throw new RuntimeException(\"Your reference number \" + refNumber +\n                  \" is bigger than number of matching tokens: \" + patternTokens.length);\n        }\n        if (result.containsKey(key)) {\n          throw new RuntimeException(\"Duplicate key '\" + key + \"'\");\n        }\n        result.put(key, patternTokens[correctedRef].getToken());\n      } else {\n        result.put(key, val);\n      }\n    }\n    return result;\n  }\n\n  // when there's a 'skip', we need to adapt the reference number","sourceCodeStart":47,"sourceCodeEnd":83,"githubUrl":"https://github.com/languagetool-org/languagetool/blob/2e990059ce67d5e2a0f7f7ca5d31160c6709df4b/languagetool-core/src/main/java/org/languagetool/rules/patterns/RuleFilterEvaluator.java#L47-L83","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"<!-- before: pattern has 2 tokens, filter references token 3 -->\n<filter class=\"...\" args=\"no:\\3\"/>\n<!-- after -->\n<filter class=\"...\" args=\"no:\\2\"/>","handlingStrategy":"validation","validationCode":"int maxRef = 0;\nfor (String arg : filterArgs.split(\"\\\\s+\")) {\n  String val = arg.substring(arg.indexOf(':') + 1);\n  if (val.startsWith(\"\\\\\")) {\n    maxRef = Math.max(maxRef, Integer.parseInt(val.substring(1)));\n  }\n}\nif (maxRef > tokenPositions.size()) {\n  throw new IllegalArgumentException(\"Reference \\\\\" + maxRef + \" exceeds \" + tokenPositions.size() + \" tokens\");\n}","typeGuard":null,"tryCatchPattern":"try {\n  Map<String,String> resolved = evaluator.getResolvedArguments(filterArgs, patternTokens, pos, tokenPositions);\n} catch (RuntimeException e) {\n  if (e.getMessage().contains(\"is bigger than\")) {\n    throw new IllegalArgumentException(\"Back-reference out of range in: \" + filterArgs, e);\n  }\n  throw e;\n}","preventionTips":["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."],"tags":["java","index-out-of-range","language-tool","rule-filters"],"backgroundTag":"index-out-of-bounds","analyzedSha":"2e990059ce67d5e2a0f7f7ca5d31160c6709df4b","analyzedAt":"2026-09-06T09:20:17.015Z","contentChangedAt":"2026-09-06T09:20:17.015Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}