languagetool-org/languagetool · error · RuntimeException

No directories '1grams' ... '3grams' found in

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.

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.

Appendix: 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)