languagetool-org/languagetool · error · RuntimeException

Confusion set must be of size 2:

Error message

Confusion set must be of size 2: 

What it means

getBetterAlternativeOrNull expects each confusion set to contain exactly two candidate words (the word and its alternative). This RuntimeException is an internal invariant check that fires when a confusion set loaded from the confusion data has a size other than 2.

Source

Thrown at languagetool-core/src/main/java/org/languagetool/rules/ngrams/ConfusionProbabilityRule.java:297

  public void setConfusionPair(ConfusionPair pair) {
    wordToPairs.clear();
    for (ConfusionString word : pair.getTerms()) {
      wordToPairs.put(word.getString(), Collections.singletonList(pair));
    }
  }

  /**
   * Returns the ngram level used, typically 3.
   * @since 3.1
   */
  public int getNGrams() {
    return grams;
  }

  @Nullable
  private ConfusionString getBetterAlternativeOrNull(GoogleToken token, List<GoogleToken> tokens, List<ConfusionString> confusionSet, long factor) {
    if (confusionSet.size() != 2) {
      throw new RuntimeException("Confusion set must be of size 2: " + confusionSet);
    }
    ConfusionString other = getAlternativeTerm(confusionSet, token);
    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;

View on GitHub (pinned to 2e990059ce)

Solutions

  1. Inspect the confusion set printed in the message and find its source entry in the language's confusion data.
  2. Ensure each confusion set has exactly two entries.
  3. Re-generate or re-download the confusion data for the language if it was modified.

Example fix

// before (confusion data: 1 entry)
their
// after (confusion data: 2 entries)
their
there
Defensive patterns

Strategy: validation

Validate before calling

// validate confusion data sets are pairs before running rules
confusionSets.forEach((word, set) -> {
    if (set.size() != 2) throw new IllegalStateException("Confusion set must be size 2: " + word + " -> " + set);
});

Try / catch

try { rule.match(...); } catch (RuntimeException e) { if (e.getMessage().startsWith("Confusion set must be of size 2")) { log.error("Corrupt confusion data: " + e.getMessage()); } throw e; }

Prevention

When it happens

Trigger: A confusion set loaded from the language's confusion data resource contains one or more than two entries, then the rule tries to compute the better alternative during rule matching.

Common situations: Malformed or hand-edited confusion-set data files; a data update changed the set format; case-related duplicates collapsed into one entry.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


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