languagetool-org/languagetool · error · RuntimeException

IOException while initializing spellers

Error message

IOException while initializing spellers

What it means

MorfologikUkrainianSpellerRule.getSpeller1() lazily initializes the Morfologik spellers by calling isMisspelled("1") (which triggers initSpellers()); if that initialization throws an IOException it is wrapped in a RuntimeException. The speller dictionaries are compiled binary resources loaded from the classpath, so an IOException here means the dictionary data could not be read.

Source

Thrown at languagetool-language-modules/uk/src/main/java/org/languagetool/rules/uk/MorfologikUkrainianSpellerRule.java:182

  @Override
  protected List<SuggestedReplacement> filterSuggestions(List<SuggestedReplacement> suggestions) {
    suggestions = super.filterSuggestions(suggestions);
    // do not suggest "кіно прокат, вело- прогулянка...":
    suggestions.removeIf(item -> item.getReplacement().contains(" ") &&
        DO_NOT_SUGGEST_SPACED_PATTERN.matcher(item.getReplacement()).matches() ||
        item.getReplacement().contains("- "));
    return suggestions;
  }

  // workaround to allow other rules generate spelling suggestions without invoking match()
  MorfologikMultiSpeller getSpeller1() {
    if( speller1 == null ) {
      try {
        // we can't call initSpellers() as it's private so we're calling method we can
        isMisspelled("1");
      } catch (IOException e) {
        throw new RuntimeException(e);
      }
    }
    return speller1;
  }

  @Override
  protected boolean isLatinScript() {
    return false;
  }
}

View on GitHub (pinned to 2e990059ce)

Solutions

  1. Verify the Morfologik dictionary resources exist in the languagetool-language-modules/uk jar (unzip -l and look for *.dict).
  2. Rebuild/reinstall the language module so resources are packaged correctly.
  3. Run with the original (non-shaded) LanguageTool jars to avoid resource filtering stripping binary files.
  4. Inspect e.getCause() for the true failure (file corruption, permissions, classpath) and fix that.
  5. Pre-initialize spellers at startup in a guarded block so failures surface with clear diagnostics before serving traffic.

Example fix

// before
MorfologikMultiSpeller speller = rule.getSpeller1(); // throws RuntimeException on bad resource
// after
try {
  MorfologikMultiSpeller speller = rule.getSpeller1();
} catch (RuntimeException e) {
  LOG.error("Ukrainian speller init failed; check uk dictionary resources on classpath", e);
}
Defensive patterns

Strategy: try-catch

Validate before calling

try (InputStream in = getClass().getResourceAsStream("/uk/ukrainian.dict")) {
  if (in == null) throw new IllegalStateException("Ukrainian speller dictionary missing from classpath");
}

Try / catch

try {
  MorfologikMultiSpeller speller = rule.getSpeller1();
} catch (RuntimeException e) {
  if (e.getCause() instanceof IOException) { LOG.error("Speller dictionary unreadable; disable spell check for uk", e); }
  else throw e;
}

Prevention

When it happens

Trigger: First call to getSpeller1() (directly or via the first spell-check) when the Morfologik .dict/.info resources cannot be opened from the classpath, e.g. corrupted jar, missing resource, or I/O failure reading the binary dictionary.

Common situations: Incomplete/dependency-broken build where Ukrainian spelling resources weren't packaged; running from a shaded jar that excluded binary resources; running inside a container with a broken or partially extracted jar; classpath isolation (app servers) hiding resources.

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/6d0dab31efb566ea. Report an issue: GitHub.