{"record":{"id":"4badd475a703c0be","repo":"languagetool-org/languagetool","slug":"error-analyzing-sentence-match-getsentence","errorCode":null,"errorMessage":"Error analyzing sentence: '\" + match.getSentence().getText() + \"' with rule \" + match.getRule().getFullId()","messagePattern":"Error analyzing sentence: '\" \\+ match\\.getSentence\\(\\)\\.getText\\(\\) \\+ \"' with rule \" \\+ match\\.getRule\\(\\)\\.getFullId\\(\\)","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"languagetool-language-modules/fr/src/main/java/org/languagetool/rules/fr/WordWithDeterminerFilter.java","lineNumber":86,"sourceCode":"      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());\n    AnalyzedToken atDeterminer = getAnalyzedToken(atrDeterminer, detPattern);\n    AnalyzedToken atWord = getAnalyzedToken(atrWord, wordPattern);\n    if (atWord == null || atDeterminer == null) {\n      throw new RuntimeException(\n          \"Error analyzing sentence: '\" + match.getSentence().getText() + \"' with rule \" + match.getRule().getFullId());\n    }\n    boolean isNoun = atWord.getPOSTag().startsWith(\"N\") || atWord.getPOSTag().startsWith(\"Z\");\n    boolean isAdjective = atWord.getPOSTag().startsWith(\"J\");\n    // boolean isParticiple = atWord.getPOSTag().startsWith(\"V\");\n\n    String prefix = \"[ZNJ] \";\n    if (isNoun && !isAdjective) {\n      prefix = \"[NZ] \";\n    } else if (!isNoun && isAdjective) {\n      prefix = \"J \";\n    }\n\n    // synthesize all forms\n    String[][] determinerForms = new String[4][];\n    String[][] wordForms = new String[4][];\n    for (int i = 0; i < 4; i++) {\n      determinerForms[i] = FrenchSynthesizer.INSTANCE.synthesize(atDeterminer, determiner + genderNumber[i], true);","sourceCodeStart":68,"sourceCodeEnd":104,"githubUrl":"https://github.com/languagetool-org/languagetool/blob/2e990059ce67d5e2a0f7f7ca5d31160c6709df4b/languagetool-language-modules/fr/src/main/java/org/languagetool/rules/fr/WordWithDeterminerFilter.java#L68-L104","documentation":"This RuntimeException is thrown when getAnalyzedToken could not produce an AnalyzedToken for either the determiner or the word at the configured positions — i.e. tagger/disambiguator output has no reading matching the expected pattern. It wraps sentence/rule identification so the offending XML rule can be located.","triggerScenarios":"acceptRuleMatch calls getAnalyzedToken(atrDeterminer, detPattern) or getAnalyzedToken(atrWord, wordPattern) and receives null, typically because the token at the given position has no POS tag matching the filter's expectation (e.g. pos tag regex in the filter finds no reading).","commonSituations":"Rules firing on unanalyzed/unknown tokens (proper nouns, typos, foreign words); French tagger lacking a dictionary entry; positions pointing at punctuation after a pattern change.","solutions":["Inspect the sentence tokens at the positions given by wordFrom/determinerFrom and confirm the tagger assigns a POS tag there.","Add the missing word/form to the French spelling/POS dictionary or adjust the rule's exception settings so it doesn't match unknown tokens.","Relax or correct the token pattern used by getAnalyzedToken so an existing reading matches.","If you control the code, add a null-safe fallback instead of throwing when analysis is inconclusive."],"exampleFix":"// before\nAnalyzedToken atWord = getAnalyzedToken(atrWord, wordPattern);\nif (atWord == null) throw new RuntimeException(...);\n// after\nAnalyzedToken atWord = getAnalyzedToken(atrWord, wordPattern);\nif (atWord == null) return true; // skip rule gracefully for unanalyzed tokens","handlingStrategy":"try-catch","validationCode":"AnalyzedTokenReadings atr = patternTokens[posWord - 1];\nif (atr.getAnalyzedTokens().isEmpty()) return true; // skip unanalyzed token","typeGuard":"static boolean hasReading(AnalyzedTokenReadings atr) { return atr != null && atr.getReadings().size() > 0; }","tryCatchPattern":"try { return filter.acceptRuleMatch(match); } catch (RuntimeException e) { log.warn(\"Filter analysis failed for rule \" + match.getRule().getFullId(), e); return true; }","preventionTips":["Add unknown words likely to appear in your texts to the dictionary","Test rules against sentences containing proper nouns and typos","Treat null analysis results as 'rule does not apply' rather than crashing"],"tags":["java","languagetool","pos-tagging","french"],"backgroundTag":"unexpected-api-response-shape","analyzedSha":"2e990059ce67d5e2a0f7f7ca5d31160c6709df4b","analyzedAt":"2026-09-06T09:20:17.015Z","contentChangedAt":"2026-09-06T09:20:17.015Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}