languagetool-org/languagetool · error · RuntimeException

Remote rules configuration file cannot be found:

Error message

Remote rules configuration file cannot be found: 

What it means

The 'remoteRulesFile' property points to a configuration file for remote rules (e.g. remotely managed rule settings). When the configured path does not exist or is not a regular file, HTTPServerConfig throws this RuntimeException at startup because remote rule configuration cannot be loaded.

Solutions

  1. Correct the 'remoteRulesFile' property to point at an existing regular file (absolute path recommended)
  2. Check file existence with 'ls -l <path>' and fix permissions if unreadable
  3. Remove the 'remoteRulesFile' property if remote rules are not used

Example fix

// before (server.properties)
remoteRulesFile=/etc/languagetool/remote-rules.conf

// after: file deployed first, or property removed
# remoteRulesFile removed (not using remote rules)
Defensive patterns

Strategy: validation

Validate before calling

String p = props.getProperty("remoteRulesFile");
if (p != null && !new File(p).isFile()) {
    throw new IllegalStateException("remoteRulesFile missing or not a regular file: " + p);
}

Try / catch

try {
    serverConfig = new HTTPServerConfig(props);
} catch (RuntimeException e) {
    if (e.getMessage().startsWith("Remote rules configuration file cannot be found")) {
        log.error("remoteRulesFile path invalid: {}", e.getMessage());
    }
    throw e;
}

Prevention

When it happens

Trigger: Starting the HTTP server with 'remoteRulesFile=/path' where the path is missing, is a directory, or the file was not synced to the machine/container running the server.

Common situations: Config copied between servers without copying the remote rules file; path valid on the admin workstation but not on the server; directory passed instead of file; permission staging scripts failed silently.

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/fb1c02974afa4c2a. Report an issue: GitHub.

Appendix: source

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

          throw new IllegalArgumentException("Invalid value for textCheckerQueueSize, must be >= 1: " + textCheckerQueueSize);
        }

        boolean atdMode = getOptionalProperty(props, "mode", "LanguageTool").equalsIgnoreCase("AfterTheDeadline");
        if (atdMode) {
          throw new IllegalArgumentException("The AfterTheDeadline mode is not supported anymore in LanguageTool 3.8 or later");
        }
        String rulesConfigFilePath = getOptionalProperty(props, "rulesFile", null);
        if (rulesConfigFilePath != null) {
          rulesConfigFile = new File(rulesConfigFilePath);
          if (!rulesConfigFile.exists() || !rulesConfigFile.isFile()) {
            throw new RuntimeException("Rules Configuration file cannot be found: " + rulesConfigFile);
          }
        }
        String remoteRulesConfigFilePath = getOptionalProperty(props, "remoteRulesFile", null);
        if (remoteRulesConfigFilePath != null) {
          remoteRulesConfigFile = new File(remoteRulesConfigFilePath);
          if (!remoteRulesConfigFile.exists() || !remoteRulesConfigFile.isFile()) {
            throw new RuntimeException("Remote rules configuration file cannot be found: " + remoteRulesConfigFile);
          }
        }
        cacheSize = Integer.parseInt(getOptionalProperty(props, "cacheSize", "0"));
        if (cacheSize < 0) {
          throw new IllegalArgumentException("Invalid value for cacheSize: " + cacheSize + ", use 0 to deactivate cache");
        }
        if (props.containsKey("cacheTTLSeconds") && !props.containsKey("cacheSize")) {
          throw new IllegalArgumentException("Use of cacheTTLSeconds without also setting cacheSize has no effect.");
        }
        cacheTTLSeconds = Integer.parseInt(getOptionalProperty(props, "cacheTTLSeconds", "300"));
        maxErrorsPerWordRate = Float.parseFloat(getOptionalProperty(props, "maxErrorsPerWordRate", "0"));
        suggestionsEnabled = Boolean.parseBoolean(getOptionalProperty(props, "suggestionsEnabled", "true"));
        maxSpellingSuggestions = Integer.parseInt(getOptionalProperty(props, "maxSpellingSuggestions", "0"));
        blockedReferrers = Arrays.asList(getOptionalProperty(props, "blockedReferrers", "").split(",\\s*"));
        setTrustedSources(getOptionalProperty(props, "trustedSources", null));
        String premiumAlwaysValue = props.getProperty("premiumAlways");
        if (premiumAlwaysValue != null) {
          premiumAlways = Boolean.parseBoolean(premiumAlwaysValue.trim());

View on GitHub (pinned to 2e990059ce)