languagetool-org/languagetool · error · RuntimeException
Not found in set '
Error message
Not found in set '
What it means
getConfusionString looks up the confusion-set entry that case-insensitively equals the token from the text. This RuntimeException is thrown when no entry matches, meaning the token extracted from text is not present in its expected confusion set.
Solutions
- Inspect the token and set in the message; verify the token's exact casing/content.
- Check the confusion data for the missing word and re-add it if removed.
- Adjust token normalization before lookup if case/locale transformations change the token.
Example fix
// before (data updated but word removed)
// confusion set: {there} while text token is 'their'
// after
// re-add to confusion data:
their Defensive patterns
Strategy: try-catch
Validate before calling
// pre-check that the token appears in the confusion set before matching
boolean present = set.stream().anyMatch(s -> s.getString().equalsIgnoreCase(token));
if (!present) log.warn("Token not in confusion set: " + token); Try / catch
try { rule.match(...); } catch (RuntimeException e) { if (e.getMessage().startsWith("Not found in set")) { log.error("Token missing from confusion data: " + e.getMessage()); } throw e; } Prevention
- Keep rule patterns and confusion data in sync
- Re-add removed words when data files change
- Test rules against sample text covering case variants
When it happens
Trigger: stringFromText extracts a token (often uppercase or differently inflected) that does not case-insensitively equal any confusion-set entry, then getConfusionString fails.
Common situations: Case conversion differences (e.g. sentence-initial capitalization combined with all-uppercase tokens); language data updates removing a word still matched by the rule pattern.
Understand the failure class
Background: Record Not Found Errors: "not found", RecordNotFound, and "was not found" — what they mean and how to fix them — this error's family across 28 libraries.
Related errors
- Confusion set must be of size 2:
- grams must be between 1 and 5:
- No alternative found for:
- AbstractAdvancedSynthesizerFilter only works with pattern…
- beolingusFile not found:
AI-assisted analysis of languagetool-org/languagetool@2e990059ce (2026-09-06).
Data as JSON: /api/errors/efd850f5fef910ae.
Report an issue: GitHub.
Appendix: source
Thrown at languagetool-core/src/main/java/org/languagetool/rules/ngrams/ConfusionProbabilityRule.java:318
return getBetterAlternativeOrNull(token, tokens, other, factor);
}
private ConfusionString getAlternativeTerm(List<ConfusionString> confusionSet, GoogleToken token) {
for (ConfusionString s : confusionSet) {
if (!s.getString().equals(token.token)) {
return s;
}
}
throw new RuntimeException("No alternative found for: " + token);
}
private ConfusionString getConfusionString(List<ConfusionString> confusionSet, GoogleToken token) {
for (ConfusionString s : confusionSet) {
if (s.getString().equalsIgnoreCase(token.token)) {
return s;
}
}
throw new RuntimeException("Not found in set '" + confusionSet + "': " + token);
}
private ConfusionString getBetterAlternativeOrNull(GoogleToken token, List<GoogleToken> tokens, ConfusionString otherWord, long factor) {
String word = token.token;
double p1;
double p2;
if (grams == 3) {
p1 = LanguageModelUtils.get3gramProbabilityFor(language, lm, token, tokens, word);
p2 = LanguageModelUtils.get3gramProbabilityFor(language, lm, token, tokens, otherWord.getString());
} else if (grams == 4) {
p1 = LanguageModelUtils.get4gramProbabilityFor(language, lm, token, tokens, word);
p2 = LanguageModelUtils.get4gramProbabilityFor(language, lm, token, tokens, otherWord.getString());
} else {
throw new RuntimeException("Only 3grams and 4grams are supported");
}
debug("%.90f <- P(" + word + ") \n", p1);
debug("%.90f <- P(" + otherWord + ")\n", p2);
return p2 >= MIN_PROB && p2 > p1 * factor ? otherWord : null;View on GitHub (pinned to 2e990059ce)