languagetool-org/languagetool · error · RuntimeException

Directory must contain at least '1grams', '2grams', and '3gr

Error message

Directory must contain at least '1grams', '2grams', and '3grams': ${topIndexDir.getAbsolutePath()}

What it means

LuceneSingleIndexLanguageModel validates that the ngram index directory contains subdirectories named '1grams', '2grams', '3grams'. If the top directory contains none of these, validateDirectory throws RuntimeException naming the path.

Source

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

   * Throw RuntimeException is the given directory does not seem to be a valid ngram top directory
   * with sub directories {@code 1grams} etc.
   * @since 3.0
   */
  public static void validateDirectory(File topIndexDir) {
    if (!topIndexDir.exists() || !topIndexDir.isDirectory()) {
      throw new RuntimeException("Not found or is not a directory:\n" +
              topIndexDir + "\n" +
              "As ngram directory, please select the directory that has a subdirectory like 'en'\n" +
              "(or whatever language code you're using).");
    }
    List<String> dirs = new ArrayList<>();
    for (String name : topIndexDir.list()) {
      if (name.matches("[123]grams")) {
        dirs.add(name);
      }
    }
    if (dirs.isEmpty()) {
      throw new RuntimeException("Directory must contain at least '1grams', '2grams', and '3grams': " + topIndexDir.getAbsolutePath());
    }
    if (dirs.size() < 3) {
      throw new RuntimeException("Expected at least '1grams', '2grams', and '3grams' sub directories but only got " + dirs + " in " + topIndexDir.getAbsolutePath());
    }
  }
  
  /**
   * Only used internally. 
   * @since 3.2 
   */
  @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

View on GitHub (pinned to 2e990059ce)

Solutions

  1. Verify the path points to the directory directly containing 1grams/, 2grams/, 3grams/
  2. Fix the configuration so it references the extracted ngram index directory
  3. Download/extract the correct language ngram index from LanguageTool

Example fix

// before
LanguageModel lm = new LuceneSingleIndexLanguageModel(new File("/data")); // /data lacks *grams
// after
LanguageModel lm = new LuceneSingleIndexLanguageModel(new File("/data/en/ngrams")); // contains 1grams..3grams
Defensive patterns

Strategy: validation

Validate before calling

File[] subs = ngramDir.listFiles(File::isDirectory);
Set<String> names = Arrays.stream(subs).map(File::getName).collect(Collectors.toSet());
if (!names.containsAll(Set.of("1grams","2grams","3grams"))) throw new IllegalStateException("Ngram index incomplete: " + ngramDir);

Try / catch

try { model = new LuceneSingleIndexLanguageModel(ngramDir); } catch (RuntimeException e) { if (e.getMessage().contains("grams")) { /* fix path or re-extract data */ } throw e; }

Prevention

When it happens

Trigger: Constructing a LuceneSingleIndexLanguageModel (which calls doValidateDirectory) pointing at a directory that contains no ngram subdirectories at all — empty dir, wrong dir, or an index not yet unpacked.

Common situations: Pointing the ngram data path at the parent directory of the index, a typo in the configured path, or the ngram archive extracted to a nested folder so the *grams dirs aren't at the top level.

Related errors


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