languagetool-org/languagetool · error · IllegalArgumentException

ngramLangIdentData does not exist or is a directory (needs t

Error message

ngramLangIdentData does not exist or is a directory (needs to be a ZIP file): 

What it means

The 'ngramLangIdentData' property must point to an existing ZIP file containing n-gram language-identification data. If the path does not exist or is a directory, HTTPServerConfig throws this IllegalArgumentException at startup.

Source

Thrown at languagetool-server/src/main/java/org/languagetool/server/HTTPServerConfig.java:516

          String key = (String)o;
          if (!KNOWN_OPTION_KEYS.contains(key) && !key.matches("lang-[a-z]+-dictPath") && !key.matches("lang-[a-z]+")) {
            System.err.println("***** WARNING: ****");
            System.err.println("Key '" + key + "' from configuration file '" + file + "' is unknown. Please check the key's spelling (case is significant).");
            System.err.println("Known keys: " + KNOWN_OPTION_KEYS);
          }
        }

        addDynamicLanguages(props);
        setAbTest(getOptionalProperty(props, "abTest", null));
        setAbTestClients(getOptionalProperty(props, "abTestClients", null));
        setAbTestRollout(Integer.parseInt(getOptionalProperty(props, "abTestRollout", "100")));
        String ngramLangIdentData = getOptionalProperty(props, "ngramLangIdentData", null);
        setDefaultThirdPartyAI(Boolean.parseBoolean(getOptionalProperty(props, "defaultThirdPartyAI", "false")));

        if (ngramLangIdentData != null) {
          File dir = new File(ngramLangIdentData);
          if (!dir.exists() || dir.isDirectory()) {
            throw new IllegalArgumentException("ngramLangIdentData does not exist or is a directory (needs to be a ZIP file): " + ngramLangIdentData);
          }
          setNgramLangIdentData(dir);
        }
      }
    } catch (IOException e) {
      throw new RuntimeException("Could not load properties from '" + file + "'", e);
    }
  }

  private void addDynamicLanguages(Properties props) throws IOException {
    for (Object keyObj : props.keySet()) {
      String key = (String)keyObj;
      if (key.startsWith("lang-") && !key.contains("-dictPath")) {
        String code = key.substring("lang-".length());
        if (!code.contains("-") && code.length() != 2 && code.length() != 3) {
          throw new IllegalArgumentException("code is supposed to be a 2 (or rarely 3) character code (unless it uses a format with variant, like xx-YY): '" + code + "'");
        }
        String nameKey = "lang-" + code;

View on GitHub (pinned to 2e990059ce)

Solutions

  1. Point 'ngramLangIdentData' at the ZIP file itself (not the extracted directory)
  2. Download the ngram language-ident data package if it is missing
  3. Remove the 'ngramLangIdentData' property if this feature is not needed

Example fix

// before (server.properties)
ngramLangIdentData=/opt/languagetool/ngrams/

// after (server.properties)
ngramLangIdentData=/opt/languagetool/ngrams/langident.zip
Defensive patterns

Strategy: validation

Validate before calling

String p = props.getProperty("ngramLangIdentData");
if (p != null) {
    File f = new File(p);
    if (!f.exists() || f.isDirectory()) throw new IllegalStateException("ngramLangIdentData must be an existing ZIP file: " + p);
}

Try / catch

try {
    serverConfig = new HTTPServerConfig(props);
} catch (IllegalArgumentException e) {
    if (e.getMessage().startsWith("ngramLangIdentData does not exist")) {
        log.error("Point ngramLangIdentData at the ZIP file, not a directory: {}", e.getMessage());
    }
    throw e;
}

Prevention

When it happens

Trigger: Server properties contains 'ngramLangIdentData=/path' where the path is missing, or points to a directory instead of the expected ZIP file (e.g. extracted archives).

Common situations: Operator downloaded and unzipped the language-ident data and pointed the config at the extracted folder; file not copied to the container; wrong filename.

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


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