{"record":{"id":"2467157238291cb5","repo":"languagetool-org/languagetool","slug":"error-analyzing-sentence-sentence-with-rule","errorCode":null,"errorMessage":"Error analyzing sentence: '${sentence}' with rule ${rule.getFullId()}","messagePattern":"Error analyzing sentence: '(.+?)' with rule (.+?)","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"languagetool-core/src/main/java/org/languagetool/rules/patterns/PatternRuleMatcher.java","lineNumber":100,"sourceCode":"      doMatch(sentence, tokens, (tokenPositions, firstMatchToken, lastMatchToken, firstMarkerMatchToken, lastMarkerMatchToken) -> {\n        RuleMatch ruleMatch = createRuleMatch(tokenPositions, tokens, firstMatchToken, lastMatchToken, firstMarkerMatchToken, lastMarkerMatchToken, sentence);\n        if (ruleMatch != null) {\n          ruleMatches.add(ruleMatch);\n        }\n      });\n      RuleMatchFilter maxFilter = new RuleWithMaxFilter();\n      List<RuleMatch> filteredMatches = maxFilter.filter(ruleMatches);\n      /*if (slowMatchThreshold != null) {\n        long runTime = System.currentTimeMillis() - startTime;\n        if (runTime > slowMatchThreshold) {\n          logger.warn(\"Slow match for rule \" + rule.getFullId() + \": \" + runTime + \"ms, sentence len: \" + sentence.getText().length() + \" (threshold: \" + slowMatchThreshold + \"ms)\");\n        }\n      }*/\n      return filteredMatches.toArray(RuleMatch.EMPTY_ARRAY);\n    } catch (IOException e) {\n      throw new IOException(\"Error analyzing sentence: '\" + sentence + \"'\", e);\n    } catch (Exception e) {\n      throw new RuntimeException(\"Error analyzing sentence: '\" + sentence + \"' with rule \" + rule.getFullId(), e);\n    } finally {\n      if (key != null) {\n        currentlyActiveRules.computeIfPresent(key, (k, v) -> v - 1 > 0 ? v - 1 : null);\n      }\n    }\n  }\n\n  @Override\n  protected boolean testAllReadings(AnalyzedTokenReadings[] tokens, PatternTokenMatcher matcher, PatternTokenMatcher prevElement, int tokenNo, int firstMatchToken, int prevSkipNext) throws IOException {\n    if (tokens[tokenNo].isImmunized()) return false;\n\n    return super.testAllReadings(tokens, matcher, prevElement, tokenNo, firstMatchToken, prevSkipNext);\n  }\n\n  @Nullable\n  private RuleMatch createRuleMatch(int[] tokenPositions,\n                                    AnalyzedTokenReadings[] tokens, int firstMatchToken,\n                                    int lastMatchToken, int firstMarkerMatchToken, int lastMarkerMatchToken,","sourceCodeStart":82,"sourceCodeEnd":118,"githubUrl":"https://github.com/languagetool-org/languagetool/blob/2e990059ce67d5e2a0f7f7ca5d31160c6709df4b/languagetool-core/src/main/java/org/languagetool/rules/patterns/PatternRuleMatcher.java#L82-L118","documentation":"The catch-all branch of PatternRuleMatcher.match(): any non-IOException thrown while applying a pattern rule to a sentence is rethrown as RuntimeException('Error analyzing sentence: ...' with rule <fullId>). It names the failing rule so you can pinpoint the broken pattern definition. The cause is chained.","triggerScenarios":"getMatches -> match() when rule matching throws any RuntimeException/Error, e.g. IndexOutOfBounds/ClassCast from a malformed pattern token, regex PatternSyntaxException at match time, or NullPointerException in a tokenizer interacting with the rule.","commonSituations":"Hand-written rule XML with invalid regex or wrong attribute combinations that only fails when applied to a particular sentence; version upgrade changing PatternToken semantics; negative-scope or case-sensitivity attributes misused in custom rules.","solutions":["Read rule.getFullId() from the message and test that specific rule against the failing sentence.","Inspect e.getCause() (e.g. PatternSyntaxException) and fix the rule's regex or token attributes.","Validate the rule XML against LanguageTool's rule schema and simplify the pattern to isolate the offending token.","Catch RuntimeException around getMatches per-rule and disable/report the broken rule at runtime."],"exampleFix":"// before\n<token regexp=\"[a-z+\"/>\n// after\n<token regexp=\"[a-z]+\"/>","handlingStrategy":"try-catch","validationCode":"// pre-compile all regexes used in rules at load time\nfor (String re : ruleRegexes) Pattern.compile(re); // throws PatternSyntaxException early","typeGuard":null,"tryCatchPattern":"try {\n  matches = matcher.match(sentence...);\n} catch (RuntimeException e) {\n  logger.error(\"Rule \" + failingRuleId + \" failed: \" + e.getCause());\n  disabledRules.add(failingRuleId);\n}","preventionTips":["Pre-compile every regex in custom rules at load time to fail fast.","Validate rule XML structure against the LanguageTool rule schema.","Isolate and unit-test each custom rule with representative sentences.","After upgrades, re-run rule tests; attribute semantics can change."],"tags":["runtime","pattern-matching","regex","java"],"backgroundTag":"invalid-regex-pattern","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"}