languagetool-org/languagetool · warning · ErrorRateTooHighException
ErrorRateTooHigh is reached by a single sentence after rule:
Error message
ErrorRateTooHigh is reached by a single sentence after rule: <rule.getFullId()>. The whole text contains <wordCounter> words and this sentence has <sentenceMatches.size()> matches.
What it means
During check(), if the number of matches in a single sentence exceeds the configured maxErrorsPerWordRate (and the text has more than 25 words), LanguageTool logs the offending rule and throws ErrorRateTooHighException. This protects servers from pathological texts that would produce enormous, useless result sets.
Source
Thrown at languagetool-core/src/main/java/org/languagetool/JLanguageTool.java:1617
}
if (checkCancelledCallback != null && checkCancelledCallback.checkCancelled()) {
break;
}
RuleMatch[] thisMatches = rule.match(analyzedSentence);
Collections.addAll(sentenceMatches, thisMatches);
if (wordCounter > 0) {
//check if the maxErrorsPerWordRate is already reached for the full text with this sentence and rule
float errorsPerWord = sentenceMatches.size() / (float) wordCounter;
if (tmpErrorsPerWord < errorsPerWord) {
errorRateLog.add("With rule: " + rule.getFullId() + " " + (i+1) + "/" + rulesSize + " the sentence error rate increased by: " + (errorsPerWord - tmpErrorsPerWord) + " from: " + tmpErrorsPerWord + " to total: " + errorsPerWord);
tmpErrorsPerWord = errorsPerWord;
}
if (maxErrorsPerWordRate > 0 && errorsPerWord > maxErrorsPerWordRate && wordCounter > 25) {
errorRateLog.forEach(e -> logger.info(LoggingTools.BAD_REQUEST, e));
logger.info(LoggingTools.BAD_REQUEST, "ErrorRateTooHigh is reached by a single sentence after rule: " + rule.getFullId() + ". " +
"The whole text contains " + wordCounter + " words " +
" and this sentence has " + sentenceMatches.size() + " matches.");
throw new ErrorRateTooHighException("ErrorRateTooHigh is reached by a single sentence after rule: " + rule.getFullId() + ". " +
"The whole text contains " + wordCounter + " words " +
"and this sentence has " + sentenceMatches.size() + " matches.");
}
}
}
if (sentenceMatches.isEmpty()) {
return sentenceMatches;
}
AnnotatedText text = new AnnotatedTextBuilder().addText(analyzedSentence.getText()).build();
// rules can create matches with rule IDs different from the original rule (see e.g. RemoteRules)
// so while we can't avoid execution of these rules, we still want disabling them to work
// so do another pass with ignoreRule here
sentenceMatches = sentenceMatches.stream()
.filter(match -> !ignoreRule(match.getRule())).collect(Collectors.toList());
return applyCustomFilters(new SameRuleGroupFilter().filter(sentenceMatches), text);
}
View on GitHub (pinned to 2e990059ce)
Solutions
- Inspect rule.getFullId() in the message — a specific rule is firing excessively; disable or tighten it if it is a custom rule.
- Check the submitted text: if it is garbage/non-prose input, validate or sanitize it before checking.
- Raise maxErrorsPerWordRate if your legitimate use case produces dense errors.
- Catch ErrorRateTooHighException in server code and return a clean 4xx-style response to the client.
Example fix
// before
List<RuleMatch> matches = lt.check(userText); // throws on garbage input
// after
try {
List<RuleMatch> matches = lt.check(userText);
} catch (ErrorRateTooHighException e) {
return badRequest("Text rejected: error rate too high (" + e.getMessage() + ")");
} Defensive patterns
Strategy: try-catch
Validate before calling
// reject obviously non-prose input before checking
if (text.chars().filter(Character::isLetter).count() * 100 / text.length() < 40) {
throw new IllegalArgumentException("input does not look like natural-language text");
} Try / catch
try {
return lt.check(text);
} catch (ErrorRateTooHighException e) {
log.warn("Rejected text: {}", e.getMessage());
throw new WebApplicationException(422);
} Prevention
- Sanitize/validate input is natural prose before calling check().
- Catch ErrorRateTooHighException explicitly in server handlers.
- Review custom rules whose fullId appears in these exceptions.
- Tune maxErrorsPerWordRate to your domain's expected error density.
When it happens
Trigger: Checking a text where one sentence produces a match density above maxErrorsPerWordRate after some rule (rule.getFullId() names it), with total text length > 25 words. Configured via the error-rate/maximum-error settings of JLanguageTool.
Common situations: Posting garbage/random character strings or encrypted/minified text to a LanguageTool server; a overly broad custom or regex rule matching far too often; non-natural-language input (code, base64) submitted for proofreading.
Related errors
- Text checking was stopped due to too many errors (more than
- No ngram data found for:
- Expected semicolon-separated input:
- Error: Lines from the input file should contain at least two
AI-assisted analysis of languagetool-org/languagetool@2e990059ce (2026-09-06).
Data as JSON: /api/errors/c68acf1706685db0.
Report an issue: GitHub.