{"record":{"id":"5969f02c2cf7e5cf","repo":"languagetool-org/languagetool","slug":"confusioncheckfilter-index-out-of-bounds-in-m-5969f0","errorCode":null,"errorMessage":"ConfusionCheckFilter: Index out of bounds in \" + match.getRule().getFullId() + \", PronounFrom: \" + posPronoun","messagePattern":"ConfusionCheckFilter: Index out of bounds in \" \\+ match\\.getRule\\(\\)\\.getFullId\\(\\) \\+ \", PronounFrom: \" \\+ posPronoun","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"languagetool-language-modules/fr/src/main/java/org/languagetool/rules/fr/InterrogativeVerbFilter.java","lineNumber":68,"sourceCode":"    morfologikRule = French.getInstance().getDefaultSpellingRule();\n  }\n\n  @Override\n  public RuleMatch acceptRuleMatch(RuleMatch match, Map<String, String> arguments, int patternTokenPos,\n                                   AnalyzedTokenReadings[] patternTokens, List<Integer> tokenPositions) throws IOException {\n    /*if (match.getSentence().getText().contains(\"Peut je\")) {\n      int ii=0;\n      ii++;\n    }*/\n    List<String> replacements = new ArrayList<>();\n    String pronounFrom = getRequired(\"PronounFrom\", arguments);\n    String verbFrom = getRequired(\"VerbFrom\", arguments);\n    String desiredPostag = null;\n    List<String> extraSuggestions = new ArrayList<>();\n    if (pronounFrom != null && verbFrom != null) {\n      int posPronoun = Integer.parseInt(pronounFrom);\n      if (posPronoun < 1 || posPronoun > patternTokens.length) {\n        throw new IllegalArgumentException(\"ConfusionCheckFilter: Index out of bounds in \" + match.getRule().getFullId()\n            + \", PronounFrom: \" + posPronoun);\n      }\n      int posVerb = Integer.parseInt(verbFrom);\n      if (posVerb < 1 || posVerb > patternTokens.length) {\n        throw new IllegalArgumentException(\n            \"ConfusionCheckFilter: Index out of bounds in \" + match.getRule().getFullId() + \", VerbFrom: \" + posVerb);\n      }\n\n      //AnalyzedTokenReadings atrVerb = patternTokens[posVerb - 1];\n      AnalyzedTokenReadings atrPronoun = patternTokens[posPronoun - 1];\n      \n      // vous\n      if (atrPronoun.matchesPosTagRegex(\"R pers obj 2 p\")) {\n        desiredPostag = \"V.* (imp) [23] [sp]|V .*(ind|cond).* 2 p\";\n      }\n      // nous\n      else if (atrPronoun.matchesPosTagRegex(\"R pers obj 1 p\")) {\n        desiredPostag = \"V.* (imp) .*|V .*(ind|cond).* 1 p\";","sourceCodeStart":50,"sourceCodeEnd":86,"githubUrl":"https://github.com/languagetool-org/languagetool/blob/2e990059ce67d5e2a0f7f7ca5d31160c6709df4b/languagetool-language-modules/fr/src/main/java/org/languagetool/rules/fr/InterrogativeVerbFilter.java#L50-L86","documentation":"InterrogativeVerbFilter.acceptRuleMatch reads a 1-based 'PronounFrom' token position from the rule's filter arguments and validates it against the pattern's token count. This IllegalArgumentException is thrown when the parsed value is < 1 or greater than the number of pattern tokens, i.e. the rule XML points at a token that does not exist in the matched sentence's token window.","triggerScenarios":"A rule declares args like \"PronounFrom:5\" but the pattern it attaches to matches only, say, 3 tokens; or the argument is 0/negative/miscounted because tokens were added/removed from the pattern during a rule edit.","commonSituations":"After editing a rule's token list, positional arguments were not renumbered; off-by-one mistakes (1-based indexing misunderstood); reusable rules whose patterns have different lengths sharing the same filter args.","solutions":["Recount the tokens in the rule's <pattern> and set PronounFrom to the correct 1-based index (1..patternTokens.length).","Renumber all positional args (PronounFrom, VerbFrom) after any pattern edit.","Add a startup-time test (LanguageTool rule tests) covering the pattern so out-of-range positions fail in CI, not at runtime."],"exampleFix":"<!-- before: pattern has 3 tokens, arg points to 5 -->\n<filter class=\"...InterrogativeVerbFilter\" args=\"PronounFrom:5 VerbFrom:2\"/>\n<!-- after -->\n<filter class=\"...InterrogativeVerbFilter\" args=\"PronounFrom:3 VerbFrom:2\"/>","handlingStrategy":"validation","validationCode":"int pronounFrom = Integer.parseInt(args.get(\"PronounFrom\"));\nint patternLen = patternTokens.length;\nif (pronounFrom < 1 || pronounFrom > patternLen) {\n    throw new IllegalArgumentException(\"PronounFrom 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":["Recount pattern tokens after every rule edit and renumber positional args.","Remember positions are 1-based.","Add rule unit tests so bad positions fail in CI."],"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"}