languagetool-org/languagetool · critical · RuntimeException

Could not load properties from ''

Error message

Could not load properties from ''

What it means

HTTPServerConfig loads the server's Properties object from the configured properties file. If reading that file throws an IOException, it is rethrown as a RuntimeException 'Could not load properties from <file>' with the original IOException as the cause, so startup fails loudly.

Source

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

        }

        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;
        String name = props.getProperty(nameKey);
        String dictPathKey = "lang-" + code + "-dictPath";
        String dictPath = props.getProperty(dictPathKey);
        if (dictPath == null) {
          throw new IllegalArgumentException(dictPathKey + " must be set");
        }

View on GitHub (pinned to 2e990059ce)

Solutions

  1. Check the file path passed to the server config option and correct it
  2. Verify read permissions for the user running the LanguageTool server (ls -l, chmod/chown)
  3. Inspect the wrapped IOException (the 'Caused by' of the RuntimeException) for the precise cause (FileNotFoundException vs access denied)
  4. If running in Docker/K8s, ensure the config file is mounted and the mount path matches the config argument

Example fix

// before
java -cp languagetool-server.jar org.languagetool.server.HTTPServer --config ./server.propertis --port 8081

// after (correct filename)
java -cp languagetool-server.jar org.languagetool.server.HTTPServer --config /etc/languagetool/server.properties --port 8081
Defensive patterns

Strategy: try-catch

Validate before calling

File cfg = new File(configPath);
if (!cfg.isFile() || !cfg.canRead()) throw new IllegalStateException("Cannot read config file: " + configPath);

Try / catch

try {
    serverConfig = new HTTPServerConfig(file);
} catch (RuntimeException e) {
    if (e.getMessage().startsWith("Could not load properties from")) {
        log.error("Config file unreadable: {}. Cause: {}", e.getMessage(), e.getCause());
    }
    throw e;
}

Prevention

When it happens

Trigger: The properties file passed to the server (e.g. via --config or the standard server.properties location) is missing, unreadable (permissions), or fails during read (I/O error while loading).

Common situations: Wrong --config path on the command line; file permissions deny the server user access; file deleted between check and start; Docker secret not mounted.

Understand the failure class

Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.

Related errors


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