languagetool-org/languagetool · error · IOException

Error analyzing sentence: '${sentence}'

Error message

Error analyzing sentence: '${sentence}'

What it means

PatternRuleMatcher.match() catches IOExceptions raised while matching a pattern rule against a sentence and rewraps them as IOException('Error analyzing sentence: ...'). This is the IOException-only branch; other exceptions get the RuntimeException variant (error 92). The cause chain holds the underlying rule-matching failure.

Source

Thrown at languagetool-core/src/main/java/org/languagetool/rules/patterns/PatternRuleMatcher.java:98

                                       ? sentence.getPreDisambigTokensWithoutWhitespace()
                                       : sentence.getTokensWithoutWhitespace();
      doMatch(sentence, tokens, (tokenPositions, firstMatchToken, lastMatchToken, firstMarkerMatchToken, lastMarkerMatchToken) -> {
        RuleMatch ruleMatch = createRuleMatch(tokenPositions, tokens, firstMatchToken, lastMatchToken, firstMarkerMatchToken, lastMarkerMatchToken, sentence);
        if (ruleMatch != null) {
          ruleMatches.add(ruleMatch);
        }
      });
      RuleMatchFilter maxFilter = new RuleWithMaxFilter();
      List<RuleMatch> filteredMatches = maxFilter.filter(ruleMatches);
      /*if (slowMatchThreshold != null) {
        long runTime = System.currentTimeMillis() - startTime;
        if (runTime > slowMatchThreshold) {
          logger.warn("Slow match for rule " + rule.getFullId() + ": " + runTime + "ms, sentence len: " + sentence.getText().length() + " (threshold: " + slowMatchThreshold + "ms)");
        }
      }*/
      return filteredMatches.toArray(RuleMatch.EMPTY_ARRAY);
    } catch (IOException e) {
      throw new IOException("Error analyzing sentence: '" + sentence + "'", e);
    } catch (Exception e) {
      throw new RuntimeException("Error analyzing sentence: '" + sentence + "' with rule " + rule.getFullId(), e);
    } finally {
      if (key != null) {
        currentlyActiveRules.computeIfPresent(key, (k, v) -> v - 1 > 0 ? v - 1 : null);
      }
    }
  }

  @Override
  protected boolean testAllReadings(AnalyzedTokenReadings[] tokens, PatternTokenMatcher matcher, PatternTokenMatcher prevElement, int tokenNo, int firstMatchToken, int prevSkipNext) throws IOException {
    if (tokens[tokenNo].isImmunized()) return false;

    return super.testAllReadings(tokens, matcher, prevElement, tokenNo, firstMatchToken, prevSkipNext);
  }

  @Nullable
  private RuleMatch createRuleMatch(int[] tokenPositions,

View on GitHub (pinned to 2e990059ce)

Solutions

  1. Inspect e.getCause() for the underlying IOException source and fix that resource/IO issue.
  2. Verify any resources referenced by the rule (regex files, binary rule caches) are present and readable.
  3. Wrap getMatches in try-catch and degrade gracefully (skip the rule) instead of aborting the whole check.
  4. Re-encode the input sentence text as UTF-8 before passing it to the analyzer.

Example fix

// before
List<RuleMatch> m = matcher.match(analyzedText);
// after
try {
  List<RuleMatch> m = matcher.match(analyzedText);
} catch (IOException e) {
  logger.warn("Rule failed on sentence: " + e.getCause());
}
Defensive patterns

Strategy: try-catch

Try / catch

try {
  matches = matcher.match(sentence...);
} catch (IOException e) {
  logger.warn("Sentence skipped, cause: " + e.getCause());
}

Prevention

When it happens

Trigger: getMatches -> match() when an IOException occurs inside the per-rule matching loop, e.g. a token/element check needs an I/O-backed resource that fails while processing the given sentence.

Common situations: Custom rules loading resources lazily (disambiguation/regex data) and hitting a missing/corrupt resource mid-match; temp files deleted; underlying reader throwing on unusual characters in the sentence.

Understand the failure class

Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.

Related errors


AI-assisted analysis of languagetool-org/languagetool@2e990059ce (2026-09-06). Data as JSON: /api/errors/0f65f8b4f5f470dd. Report an issue: GitHub.