languagetool-org/languagetool · error · RuntimeException

No ${ngramSize}grams directory found in ${topIndexDir}

Error message

No ${ngramSize}grams directory found in ${topIndexDir}

What it means

getLuceneSearcher(ngramSize) looks up a pre-loaded LuceneSearcher for the requested ngram size in luceneSearcherMap. If no searcher was registered for that size (because no '<n>grams' directory exists under the top index directory), it throws. This typically means the index layout on disk does not match what the model was configured to load.

Source

Thrown at languagetool-core/src/main/java/org/languagetool/languagemodel/LuceneSingleIndexLanguageModel.java:173

        for (ScoreDoc scoreDoc : docs.scoreDocs) {
          long tmp = Long.parseLong(luceneSearcher.reader.document(scoreDoc.doc).get("totalTokenCount"));
          if (tmp > result) {
            // due to the way FrequencyIndexCreator adds these totalTokenCount fields, we must not sum them,
            // but take the largest one:
            result = tmp;
          }
        }
        return result;
      }
    } catch (IOException e) {
      throw new RuntimeException(e);
    }
  }

  protected LuceneSearcher getLuceneSearcher(int ngramSize) {
    LuceneSearcher luceneSearcher = luceneSearcherMap.get(ngramSize);
    if (luceneSearcher == null) {
      throw new RuntimeException("No " + ngramSize + "grams directory found in " + topIndexDir);
    }
    return luceneSearcher;
  }

  private LuceneSearcher getCachedLuceneSearcher(File indexDir) {
    LuceneSearcher luceneSearcher = dirToSearcherMap.get(indexDir);
    if (luceneSearcher == null) {
      try {
        LuceneSearcher newSearcher = new LuceneSearcher(indexDir);
        dirToSearcherMap.put(indexDir, newSearcher);
        return newSearcher;
      } catch (IOException e) {
        throw new RuntimeException(e);
      }
    } else {
      return luceneSearcher;
    }
  }

View on GitHub (pinned to 2e990059ce)

Solutions

  1. Download/use the full ngram index for the language that includes all needed '<n>grams' directories (1grams, 2grams, 3grams).
  2. Verify the top index directory contains subdirectories literally named '<n>grams' (e.g. '3grams', not '3-grams' or 'trigrams').
  3. Check extraction of the index archive completed (no truncated/missing subdirectories).
  4. Match the index release to your LanguageTool version; older indexes may have different layouts.

Example fix

// before: only 1grams/2grams present
$ ls /data/ngrams/en -> 1grams 2grams
// after: fetch full index
$ ls /data/ngrams/en -> 1grams 2grams 3grams
Defensive patterns

Strategy: validation

Validate before calling

for (int n : new int[]{1,2,3}) {
  File d = new File(topIndexDir, n + "grams");
  if (!d.isDirectory()) throw new IllegalStateException("Missing " + d);
}

Prevention

When it happens

Trigger: Calling getCount() (or anything resolving a searcher) with an ngram size whose '<n>grams' directory was not found or not registered when the model scanned topIndexDir; e.g. requesting trigram lookups when only 1grams/2grams directories exist.

Common situations: Downloading an index that ships only 1grams/2grams but running rules that need 3grams; mistyping/misplacing directories so names don't match the expected '<n>grams' pattern; incomplete archive extraction.

Understand the failure class

Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.

Related errors


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