{"record":{"id":"b5c6273da0689aba","repo":"languagetool-org/languagetool","slug":"advancedsynthesizerfilter-index-out-of-bounds-in","errorCode":null,"errorMessage":"AdvancedSynthesizerFilter: Index out of bounds in ${match.getRule().getFullId()}, value: ${postagFromStr}","messagePattern":"AdvancedSynthesizerFilter: Index out of bounds in (.+?), value: (.+?)","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"languagetool-core/src/main/java/org/languagetool/rules/AbstractAdvancedSynthesizerFilter.java","lineNumber":74,"sourceCode":"    String lemmaSelect = getRequired(\"lemmaSelect\", arguments);\n    String postagFromStr = getRequired(\"postagFrom\", arguments);\n    String lemmaFromStr = getRequired(\"lemmaFrom\", arguments);\n    String newLemma = getOptional(\"newLemma\", arguments, \"\");\n\n    int postagFrom = 0;\n    if (postagFromStr.startsWith(\"marker\")) {\n      while (postagFrom < patternTokens.length && patternTokens[postagFrom].getStartPos() < match.getFromPos()) {\n        postagFrom++;\n      }\n      postagFrom++;\n      if (postagFromStr.length()>6) {\n        postagFrom += Integer.parseInt(postagFromStr.replace(\"marker\", \"\"));\n      }\n    } else {\n      postagFrom = Integer.parseInt(postagFromStr);\n    }\n    if (postagFrom < 1 || postagFrom > patternTokens.length) {\n      throw new IllegalArgumentException(\"AdvancedSynthesizerFilter: Index out of bounds in \"\n          + match.getRule().getFullId() + \", value: \" + postagFromStr);\n    }\n    int lemmaFrom = 0;\n    if (lemmaFromStr.startsWith(\"marker\")) {\n      while (lemmaFrom < patternTokens.length && patternTokens[lemmaFrom].getStartPos() < match.getFromPos()) {\n        lemmaFrom++;\n      }\n      lemmaFrom++;\n      if (lemmaFromStr.length()>6) {\n        lemmaFrom += Integer.parseInt(lemmaFromStr.replace(\"marker\", \"\"));\n      }\n    } else {\n      lemmaFrom = Integer.parseInt(lemmaFromStr);\n    }\n    if (lemmaFrom < 1 || lemmaFrom > patternTokens.length) {\n      throw new IllegalArgumentException(\"AdvancedSynthesizerFilter: Index out of bounds in \"\n          + match.getRule().getFullId() + \", value: \" + lemmaFromStr);\n    }","sourceCodeStart":56,"sourceCodeEnd":92,"githubUrl":"https://github.com/languagetool-org/languagetool/blob/2e990059ce67d5e2a0f7f7ca5d31160c6709df4b/languagetool-core/src/main/java/org/languagetool/rules/AbstractAdvancedSynthesizerFilter.java#L56-L92","documentation":"AbstractAdvancedSynthesizerFilter.acceptRuleMatch() parses the rule's 'postagFrom' argument (absolute int or 'marker+N' offset) and validates it indexes into the matched pattern tokens (1..patternTokens.length). A value outside that range means the synthesizer rule misconfiguration references a token that doesn't exist in the match, so it throws.","triggerScenarios":"A rule using an AdvancedSynthesizerFilter supplies postagFrom (e.g. postag_from=\"5\" or postag_from=\"marker:2\" resolved value) that is <1 or greater than the number of tokens actually matched by the rule pattern.","commonSituations":"Editing a rule pattern to fewer tokens without updating postag_from; off-by-one confusion (positions are 1-based); using marker arithmetic that overshoots the token count.","solutions":["Fix postag_from in the rule XML so it points to an existing token (1-based) within the matched pattern.","Recount the rule pattern tokens after edits and update all *_from/*_to references.","Check 'marker' arithmetic: the resolved marker+N must stay within patternTokens.length.","Test the rule with LanguageTool's rule validation (e.g. via the rule editor or validateRuls tests) before deploying."],"exampleFix":"// before (pattern has 2 tokens)\n<filter class=\"...AdvancedSynthesizerFilter\" args=\"postag_from:5 lemma_from:1\"/>\n// after\n<filter class=\"...AdvancedSynthesizerFilter\" args=\"postag_from:1 lemma_from:1\"/>","handlingStrategy":"validation","validationCode":"// at rule-authoring time\nint postagFrom = Integer.parseInt(args.get(\"postag_from\").replace(\"marker\", \"\"));\nif (postagFrom < 1 || postagFrom > patternTokens.length)\n  throw new RuleFormatException(\"postag_from out of range\");","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Recheck filter arg indices whenever a rule pattern changes","Remember indices are 1-based","Keep marker arithmetic within the token count","Run rule test sentences in CI"],"tags":["grammar-rules","synthesizer","rule-configuration"],"backgroundTag":"index-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"}