languagetool-org/languagetool · critical · RuntimeException

throw new RuntimeException(e)

Error message

throw new RuntimeException(e)

What it means

UpperCaseNgramRule.initSpeller lazily creates a MorfologikAmericanSpellerRule inside a double-checked locking block; if constructing that rule throws an IOException (e.g. while loading its binary dictionary resource from the classpath), the IOException is wrapped in a RuntimeException with no additional message.

Source

Thrown at languagetool-language-modules/en/src/main/java/org/languagetool/rules/en/UpperCaseNgramRule.java:542

    addExamplePair(Example.wrong("This <marker>Prototype</marker> was developed by Miller et al."),
                   Example.fixed("This <marker>prototype</marker> was developed by Miller et al."));
    antiPatterns = cacheAntiPatterns(lang, ANTI_PATTERNS);

    initTrie();
    initSpeller();
    if (userConfig != null && linguServices == null) {
      linguServices = userConfig.getLinguServices();
    }
  }

  private void initSpeller() {
    if (spellerRule == null) {
      synchronized (UpperCaseNgramRule.class) {
        if (spellerRule == null) {
          try {
            spellerRule = new MorfologikAmericanSpellerRule(messages, lang);
          } catch (IOException e) {
            throw new RuntimeException(e);
          }
        }
      }
    }
  }

  private void initTrie() {
    if (exceptionTrie == null) {
      synchronized (UpperCaseNgramRule.class) {
        if (exceptionTrie == null) {
          exceptionTrie = new AhoCorasickDoubleArrayTrie<>();
          CachingWordListLoader cachingWordListLoader = new CachingWordListLoader();
          List<String> words = new ArrayList<>();
          words.addAll(cachingWordListLoader.loadWords("en/specific_case.txt"));
          words.addAll(cachingWordListLoader.loadWords("spelling_global.txt"));
          Map<String,String> map = new HashMap<>();
          for (String word : words) {
            map.put(word, word);

View on GitHub (pinned to 2e990059ce)

Solutions

  1. Use a complete, official languagetool-language-modules/en artifact/jar containing the Morfologik dictionary
  2. Rebuild the module fully (including spelling resource generation) if building from source
  3. Inspect the wrapped cause e for the underlying IOException (resource not found / corrupted)
  4. Verify classpath integrity: the en dictionary .dict file is present and readable

Example fix

// before
<dependency>en module built with -DskipTests and resource filtering removed dict</dependency>
// after
<dependency>
  <groupId>org.languagetool</groupId>
  <artifactId>language-en</artifactId>
  <version>matching-full-release-version</version>
</dependency>
Defensive patterns

Strategy: try-catch

Validate before calling

// verify the en dictionary resource is on the classpath before building the language
String dict = "/org/languagetool/resource/en/hunspell/en_US.dict"; // adjust to morfologik resource
if (UpperCaseNgramRule.class.getResource(dict) == null) {
  throw new IllegalStateException("English spelling data missing from classpath");
}

Try / catch

try {
  LanguageToolRuleSet rules = ...; // constructs English including UpperCaseNgramRule
} catch (RuntimeException e) {
  if (e.getCause() instanceof IOException) {
    log.error("Morfologik speller init failed — check en module jar/resources", e.getCause());
  } else throw e;
}

Prevention

When it happens

Trigger: Building an English LanguageTool instance (which constructs UpperCaseNgramRule) when the Morfologik speller dictionary resource cannot be loaded: corrupted/partial jar, missing resource after a custom build, or I/O error reading the packaged dictionary.

Common situations: Rebuilding LanguageTool without running the dictionary-preparation steps; running with a stripped/downsized jar that omitted en spelling data; classloader issues in application servers embedding LanguageTool.

Related errors


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