{"record":{"id":"b014d9ca5e39ae71","repo":"languagetool-org/languagetool","slug":"expected-at-least-1grams-2grams-and-3grams","errorCode":null,"errorMessage":"Expected at least '1grams', '2grams', and '3grams' sub directories but only got ${dirs} in ${topIndexDir.getAbsolutePath()}","messagePattern":"Expected at least '1grams', '2grams', and '3grams' sub directories but only got (.+?) in (.+?)","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"languagetool-core/src/main/java/org/languagetool/languagemodel/LuceneSingleIndexLanguageModel.java","lineNumber":72,"sourceCode":"   */\n  public static void validateDirectory(File topIndexDir) {\n    if (!topIndexDir.exists() || !topIndexDir.isDirectory()) {\n      throw new RuntimeException(\"Not found or is not a directory:\\n\" +\n              topIndexDir + \"\\n\" +\n              \"As ngram directory, please select the directory that has a subdirectory like 'en'\\n\" +\n              \"(or whatever language code you're using).\");\n    }\n    List<String> dirs = new ArrayList<>();\n    for (String name : topIndexDir.list()) {\n      if (name.matches(\"[123]grams\")) {\n        dirs.add(name);\n      }\n    }\n    if (dirs.isEmpty()) {\n      throw new RuntimeException(\"Directory must contain at least '1grams', '2grams', and '3grams': \" + topIndexDir.getAbsolutePath());\n    }\n    if (dirs.size() < 3) {\n      throw new RuntimeException(\"Expected at least '1grams', '2grams', and '3grams' sub directories but only got \" + dirs + \" in \" + topIndexDir.getAbsolutePath());\n    }\n  }\n  \n  /**\n   * Only used internally. \n   * @since 3.2 \n   */\n  @Experimental\n  public static void clearCaches() {\n    dirToSearcherMap.clear();\n  }\n\n  /**\n   * @param topIndexDir a directory which contains at least another sub directory called {@code 3grams},\n   *                    which is a Lucene index with ngram occurrences as created by\n   *                    {@code org.languagetool.dev.FrequencyIndexCreator}.\n   */\n  public LuceneSingleIndexLanguageModel(File topIndexDir)  {","sourceCodeStart":54,"sourceCodeEnd":90,"githubUrl":"https://github.com/languagetool-org/languagetool/blob/2e990059ce67d5e2a0f7f7ca5d31160c6709df4b/languagetool-core/src/main/java/org/languagetool/languagemodel/LuceneSingleIndexLanguageModel.java#L54-L90","documentation":"LuceneSingleIndexLanguageModel requires all three of '1grams', '2grams', '3grams' subdirectories. If validateDirectory finds some but fewer than three, it throws RuntimeException listing which ones were found and where.","triggerScenarios":"Constructing the model against an index directory containing only a subset of the required ngram subdirectories (e.g. only 1grams and 2grams present).","commonSituations":"Partial or corrupted download/extraction of the ngram index; manually deleting a large ngram folder to save space; a different maxNgram index layout passed to the wrong constructor.","solutions":["Re-download/re-extract the full ngram index so 1grams, 2grams and 3grams all exist","Move/copy the missing ngrams subdirectory into the index dir","Use a constructor/variant that matches the available data"],"exampleFix":"// before\nls /data/en/  ->  1grams 2grams   // 3grams missing\n// after\nunzip en-ngrams.zip -d /data/en/  # restores 1grams 2grams 3grams","handlingStrategy":"validation","validationCode":"Set<String> found = new HashSet<>();\nfor (File f : ngramDir.listFiles(File::isDirectory)) if (f.getName().matches(\"[123]grams\")) found.add(f.getName());\nif (found.size() < 3) throw new IllegalStateException(\"Missing ngram dirs, only got: \" + found);","typeGuard":null,"tryCatchPattern":"try { model = new LuceneSingleIndexLanguageModel(ngramDir); } catch (RuntimeException e) { if (e.getMessage().startsWith(\"Expected at least\")) { reDownloadNgramIndex(ngramDir); model = new LuceneSingleIndexLanguageModel(ngramDir); } else throw e; }","preventionTips":["Checksum-verify ngram archives after download to catch partial extractions","Never manually delete individual ngrams subdirectories to reclaim space","Compare the extracted directory listing against the archive before deploying"],"tags":["java","lucene","ngrams","incomplete-data"],"backgroundTag":"directory-not-found","analyzedSha":"2e990059ce67d5e2a0f7f7ca5d31160c6709df4b","analyzedAt":"2026-09-06T09:20:17.015Z","contentChangedAt":"2026-09-06T09:20:17.015Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}