languagetool-org/languagetool · error · IOException

Could not load remote rules configuration at…

Error message

Could not load remote rules configuration at <configFile.getAbsolutePath()>

What it means

The same activateRemoteRules(File) flow wraps ExecutionException from loading the remote-rule configuration as an IOException 'Could not load remote rules configuration at <path>'. Unlike [27] this comes from the ExecutionException branch, i.e. the asynchronous loading task failed while resolving/fetching the configuration.

Solutions

  1. Unwrap the ExecutionException cause to see the loader's real failure.
  2. Verify network reachability of the remote rule endpoint from the host.
  3. Check credentials/keys inside the remote-rule configuration file are valid and current.
  4. Add a fallback that runs without remote rules, or retry the activation on transient network errors.

Example fix

// before
lt.activateRemoteRules(new File("remote-rules.conf")); // throws on network failure
// after
try {
  lt.activateRemoteRules(new File("remote-rules.conf"));
} catch (IOException e) {
  logger.warn("Remote rules unavailable, continuing with local rules", e);
}
Defensive patterns

Strategy: fallback

Validate before calling

// preflight the remote endpoint referenced by the config before activation
HttpResponse<String> r = client.send(req, HttpResponse.BodyHandlers.ofString());
if (r.statusCode() != 200) throw new IllegalStateException("remote rule endpoint unhealthy");

Try / catch

try {
  lt.activateRemoteRules(configFile);
} catch (IOException e) {
  logger.warn("Remote rules unavailable (" + e.getCause() + "); using local rules only");
  // continue degraded
}

Prevention

When it happens

Trigger: Calling activateRemoteRules(File) when the underlying config-loading future fails (ExecutionException): unreachable remote-rule endpoint, invalid credentials in the config, or any exception thrown inside the loader task.

Common situations: Remote rule server down or misconfigured URL in the config; network/firewall blocking the fetch in production; expired API credentials for third-party (e.g. AI) rule backends invoked via testThirdPartyAI paths.

Related errors


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

Appendix: source

Thrown at languagetool-core/src/main/java/org/languagetool/JLanguageTool.java:647

      if (transformed != original) {
        rules.set(i, transformed);
      }
    }
  }

  public void activateRemoteRules(@Nullable File configFile) throws IOException {
    List<RemoteRuleConfig> configs;
    try {
      if (configFile != null) {
        configs = RemoteRuleConfig.load(configFile);
      } else {
        configs = Collections.emptyList();
      }
      activateRemoteRules(configs);
    } catch (IOException e) {
      throw new IOException("Could not load remote rules.", e);
    } catch (ExecutionException e) {
      throw new IOException("Could not load remote rules configuration at " + configFile.getAbsolutePath(), e);
    }
  }

  public void activateRemoteRules(List<RemoteRuleConfig> configs) throws IOException {
    // Apply A/B test filtering first - can affect which rules get enabled and thus disabled because of fallback settings
    List<String> activeAbTestsForUser = userConfig.getAbTest();
    List<RemoteRuleConfig> selectedConfigsByUserSettings = configs.stream()
      .filter(config -> {
        if (!userConfig.isPremium() && config.isPremium()) {
          return false;
        }
        String excludeABTest = config.getOptions().get("excludeABTest");
        if (excludeABTest != null && activeAbTestsForUser != null &&
          activeAbTestsForUser.stream().anyMatch(flag -> flag.matches(excludeABTest))) {
          return false;
        }
        String activeRemoteRuleAbTest = config.getOptions().get("abtest");
        if (activeRemoteRuleAbTest != null && !activeRemoteRuleAbTest.trim().isEmpty()) {

View on GitHub (pinned to 2e990059ce)