languagetool-org/languagetool · error · RuntimeException

No directories '1grams' ... '3grams' found in ${topIndexDir}

Error message

No directories '1grams' ... '3grams' found in ${topIndexDir}

What it means

After adding indexes for ngram sizes 1-4, the LuceneSingleIndexLanguageModel constructor checks whether any searcher was actually registered. If luceneSearcherMap is empty — no *grams directory existed — it throws RuntimeException.

Source

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

  @Experimental
  public static void clearCaches() {
    dirToSearcherMap.clear();
  }

  /**
   * @param topIndexDir a directory which contains at least another sub directory called {@code 3grams},
   *                    which is a Lucene index with ngram occurrences as created by
   *                    {@code org.languagetool.dev.FrequencyIndexCreator}.
   */
  public LuceneSingleIndexLanguageModel(File topIndexDir)  {
    doValidateDirectory(topIndexDir);
    this.topIndexDir = topIndexDir;
    addIndex(topIndexDir, 1);
    addIndex(topIndexDir, 2);
    addIndex(topIndexDir, 3);
    addIndex(topIndexDir, 4);
    if (luceneSearcherMap.isEmpty()) {
      throw new RuntimeException("No directories '1grams' ... '3grams' found in " + topIndexDir);
    }
    maxNgram = Collections.<Integer>max(luceneSearcherMap.keySet());
  }

  public LuceneSingleIndexLanguageModel(int maxNgram) {
    this.maxNgram = maxNgram;
    this.topIndexDir = null;
  }

  protected void doValidateDirectory(File topIndexDir) {
    validateDirectory(topIndexDir);
  }

  private void addIndex(File topIndexDir, int ngramSize) {
    File indexDir = new File(topIndexDir, ngramSize + "grams");
    if (indexDir.exists() && indexDir.isDirectory()) {
      if (luceneSearcherMap.containsKey(ngramSize)) {
        throw new RuntimeException("Searcher for ngram size " + ngramSize + " already exists");

View on GitHub (pinned to 2e990059ce)

Solutions

  1. Point the constructor at the directory containing the extracted 1grams...3grams subdirectories
  2. Extract the ngram data archive to the configured location
  3. Verify with ls that *grams directories exist before constructing

Example fix

// before
new LuceneSingleIndexLanguageModel(new File("/data/empty"));
// after
new LuceneSingleIndexLanguageModel(new File("/data/en")); // has 1grams..3grams
Defensive patterns

Strategy: validation

Validate before calling

if (ngramDir == null || !ngramDir.isDirectory()) throw new IllegalStateException("Not a directory: " + ngramDir);
boolean any = Arrays.stream(ngramDir.list()).anyMatch(n -> n.matches("[1-4]grams"));
if (!any) throw new IllegalStateException("No ngram subdirectories in " + ngramDir);

Try / catch

try { model = new LuceneSingleIndexLanguageModel(ngramDir); } catch (RuntimeException e) { if (e.getMessage().startsWith("No directories")) { /* point to correct index dir */ } throw e; }

Prevention

When it happens

Trigger: Instantiating LuceneSingleIndexLanguageModel(File topIndexDir) where topIndexDir exists but contains no 1grams/2grams/3grams/4grams directories (e.g. without the validateDirectory path having rejected it first).

Common situations: Same wrong-path problems as the validation errors: empty directory, data not yet extracted, path typo; differs from [34]/[35] only in the constructor variant used.

Related errors


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