{"record":{"id":"bd10abf901cd98bb","repo":"languagetool-org/languagetool","slug":"wordwithdeterminerfilter-index-out-of-bounds-in","errorCode":null,"errorMessage":"WordWithDeterminerFilter: Index out of bounds in \" + match.getRule().getFullId() + \", wordFrom: \" + posWord","messagePattern":"WordWithDeterminerFilter: Index out of bounds in \" \\+ match\\.getRule\\(\\)\\.getFullId\\(\\) \\+ \", wordFrom: \" \\+ posWord","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"languagetool-language-modules/fr/src/main/java/org/languagetool/rules/fr/WordWithDeterminerFilter.java","lineNumber":64,"sourceCode":"\n  private static final List<String> exceptionsDeterminer =\n    Arrays.asList(\"bels\", \"fols\", \"mols\", \"nouvels\");\n\n  private static final String categoryToCheck = \"CAT_ELISION\";\n  private static final List<String> rulesToCheck = Arrays.asList(\"CET_CE\", \"CE_CET\", \"MA_VOYELLE\", \"MON_NFS\", \"VIEUX\");\n\n  @Override\n  public RuleMatch acceptRuleMatch(RuleMatch match, Map<String, String> arguments, int patternTokenPos,\n                                   AnalyzedTokenReadings[] patternTokens, List<Integer> tokenPositions) throws IOException {\n    JLanguageTool lt = Languages.getLanguageForShortCode(\"fr\").createDefaultJLanguageTool();\n    String wordFrom = getRequired(\"wordFrom\", arguments);\n    String determinerFrom = getRequired(\"determinerFrom\", arguments);\n    int posWord = 0;\n    int posDeterminer = 0;\n    if (wordFrom != null && determinerFrom != null) {\n      posWord = Integer.parseInt(wordFrom);\n      if (posWord < 1 || posWord > patternTokens.length) {\n        throw new IllegalArgumentException(\"WordWithDeterminerFilter: Index out of bounds in \"\n            + match.getRule().getFullId() + \", wordFrom: \" + posWord);\n      }\n      posDeterminer = Integer.parseInt(determinerFrom);\n      if (posDeterminer < 1 || posDeterminer > patternTokens.length) {\n        throw new IllegalArgumentException(\"WordWithDeterminerFilter: Index out of bounds in \"\n            + match.getRule().getFullId() + \", posDeterminer: \" + posWord);\n      }\n    } else {\n      throw new IllegalArgumentException(\"WordWithDeterminerFilter: undefined parameters wordFrom or determinerFrom in \"\n          + match.getRule().getFullId());\n    }\n    AnalyzedTokenReadings atrDeterminer = patternTokens[posDeterminer - 1];\n    AnalyzedTokenReadings atrWord = patternTokens[posWord - 1];\n    boolean isDeterminerCapitalized = StringTools.isCapitalizedWord(atrDeterminer.getToken());\n    boolean isWordCapitalized = StringTools.isCapitalizedWord(atrWord.getToken());\n    boolean isDeterminerAllupper = StringTools.isAllUppercase(atrDeterminer.getToken())\n        && !atrDeterminer.getToken().equalsIgnoreCase(\"L'\");\n    boolean isWordAllupper = StringTools.isAllUppercase(atrWord.getToken());","sourceCodeStart":46,"sourceCodeEnd":82,"githubUrl":"https://github.com/languagetool-org/languagetool/blob/2e990059ce67d5e2a0f7f7ca5d31160c6709df4b/languagetool-language-modules/fr/src/main/java/org/languagetool/rules/fr/WordWithDeterminerFilter.java#L46-L82","documentation":"WordWithDeterminerFilter.acceptRuleMatch validates the 1-based 'wordFrom' filter argument against the matched pattern tokens and throws this IllegalArgumentException when posWord is < 1 or greater than patternTokens.length, meaning the rule references a word token position outside the pattern. (Note: the following posDeterminer check has a copy-paste bug — it prints posWord in its message.)","triggerScenarios":"A rule declares \"wordFrom:N\" where N is 0, negative, or larger than the number of tokens matched by the rule's <pattern>, evaluated when the rule match is post-processed by the filter.","commonSituations":"Renumbering mistakes after pattern edits; sharing args across rules with shorter patterns; confusion between the two positional args leading to swapped values.","solutions":["Set wordFrom to the correct 1-based token index within the pattern's length.","Renumber wordFrom/determinerFrom together after every pattern change and add a rule test.","Fix the adjacent bug so the posDeterminer error message prints posDeterminer, avoiding misleading diagnostics later."],"exampleFix":"<!-- before: pattern has 3 tokens, arg points to 6 -->\n<filter class=\"...WordWithDeterminerFilter\" args=\"wordFrom:6 determinerFrom:1\"/>\n<!-- after -->\n<filter class=\"...WordWithDeterminerFilter\" args=\"wordFrom:2 determinerFrom:1\"/>","handlingStrategy":"validation","validationCode":"int wordFrom = Integer.parseInt(args.get(\"wordFrom\"));\nint patternLen = patternTokens.length;\nif (wordFrom < 1 || wordFrom > patternLen) {\n    throw new IllegalArgumentException(\"wordFrom must be 1..\" + patternLen);\n}","typeGuard":null,"tryCatchPattern":"try { return filter.acceptRuleMatch(match, args, pos, tokens, tp); } catch (IllegalArgumentException e) { LOG.error(\"Rule \" + match.getRule().getFullId() + \": \" + e.getMessage()); return match; }","preventionTips":["Ensure wordFrom is a 1-based index within the pattern's token count.","Renumber wordFrom/determinerFrom after pattern edits.","Fix the diagnostic bug that prints posWord in the posDeterminer error message to avoid confusion while debugging."],"tags":["java","languagetool","index-out-of-bounds","rule-configuration","french"],"backgroundTag":"value-out-of-range","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"}