languagetool-org/languagetool · error · RuntimeException
No grams directory found in
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.
Solutions
- Download/use the full ngram index for the language that includes all needed '<n>grams' directories (1grams, 2grams, 3grams).
- Verify the top index directory contains subdirectories literally named '<n>grams' (e.g. '3grams', not '3-grams' or 'trigrams').
- Check extraction of the index archive completed (no truncated/missing subdirectories).
- 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
- Check '<n>grams' subdirectories exist before constructing the model
- Fully extract the index archive before use
- Match index release to LanguageTool version
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
- Did not expect more than 1000 'totalTokenCount' meta…
- More than 2000 matches for
- Directory must contain at least '1grams', '2grams', and…
- Exception during search for query + query + on rule +…
- Expected at least '1grams', '2grams', and '3grams' sub…
AI-assisted analysis of languagetool-org/languagetool@2e990059ce (2026-09-06).
Data as JSON: /api/errors/480df0722fba0550.
Report an issue: GitHub.
Appendix: 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)