languagetool-org/languagetool · error · IllegalArgumentException

suppressMisspelledMatch must be a valid regex

Error message

suppressMisspelledMatch must be a valid regex

What it means

RemoteRule's constructor compiles the optional service option 'suppressMisspelledMatch' as a java.util.regex.Pattern. If the option value is present but not syntactically valid regex, PatternSyntaxException is rethrown as IllegalArgumentException with this message.

Solutions

  1. Fix the suppressMisspelledMatch option value to be valid Java regex syntax (e.g. '\\bmisspelled\\b').
  2. Test the pattern with Pattern.compile() in a snippet or a regex validator set to Java flavor.
  3. Remove the option entirely if suppression is not needed (it is optional).
  4. Check escaping in the config file format (properties/JSON may require doubling backslashes).

Example fix

// before (config)
suppressMisspelledMatch=*.ogg
// after
suppressMisspelledMatch=.*\\.ogg
Defensive patterns

Strategy: try-catch

Validate before calling

String opt = serviceConfig.getOptions().get("suppressMisspelledMatch");
if (opt != null) {
  try { java.util.regex.Pattern.compile(opt); }
  catch (java.util.regex.PatternSyntaxException e) {
    throw new IllegalArgumentException("suppressMisspelledMatch is not valid regex: " + e.getMessage());
  }
}

Try / catch

try {
  rule = new RemoteRule(language, messages, config, inputLogging);
} catch (IllegalArgumentException e) {
  LOG.error("RemoteRule config rejected: {}", e.getMessage());
  throw e; // config must be fixed before retry
}

Prevention

When it happens

Trigger: Configuring a remote rule's RemoteRuleConfig options with suppressMisspelledMatch set to an invalid regex string (unbalanced parens, dangling quantifier, bad escape).

Common situations: Typing a glob-style pattern ('*.ogg') where a regex is required, escaping confusion in config/JSON files (e.g. '\\b' vs '\b'), or copy-pasting patterns with shell-mangled backslashes.

Related errors


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

Appendix: source

Thrown at languagetool-core/src/main/java/org/languagetool/rules/RemoteRule.java:91

    this.lt = this.ruleLanguage.createDefaultJLanguageTool();
    this.inputLogging = inputLogging;
    if (ruleId == null) { // allow both providing rule ID in constructor or overriding getId
      ruleId = getId();
    }
    filterMatches = Boolean.parseBoolean(serviceConfiguration.getOptions().getOrDefault("filterMatches", "false"));
    whitespaceNormalisation = Boolean.parseBoolean(serviceConfiguration.getOptions().getOrDefault("whitespaceNormalisation", "true"));
    fixOffsets = Boolean.parseBoolean(serviceConfiguration.getOptions().getOrDefault("fixOffsets", "true"));
    premium = Boolean.parseBoolean(serviceConfiguration.getOptions().getOrDefault("premium", "false"));
    boolean includedInHiddenMatches = Boolean.parseBoolean(serviceConfiguration.getOptions().getOrDefault("includedInHiddenMatches", "true"));
    setIncludedInHiddenMatches(includedInHiddenMatches);
    try {
      if (serviceConfiguration.getOptions().containsKey("suppressMisspelledMatch")) {
        suppressMisspelledMatch = Pattern.compile(serviceConfiguration.getOptions().get("suppressMisspelledMatch"));
      } else {
        suppressMisspelledMatch = null;
      }
    } catch(PatternSyntaxException e) {
      throw new IllegalArgumentException("suppressMisspelledMatch must be a valid regex", e);
    }
    try {
      if (serviceConfiguration.getOptions().containsKey("suppressMisspelledSuggestions")) {
        suppressMisspelledSuggestions = Pattern.compile(serviceConfiguration.getOptions().get("suppressMisspelledSuggestions"));
      } else {
        suppressMisspelledSuggestions = null;
      }
    } catch(PatternSyntaxException e) {
      throw new IllegalArgumentException("suppressMisspelledSuggestions must be a valid regex", e);
    }
  }

  public RemoteRule(Language language, ResourceBundle messages, RemoteRuleConfig config, boolean inputLogging) {
    this(language, messages, config, inputLogging, null);
  }

  public static void shutdown() {
    shutdownRoutines.forEach(Runnable::run);

View on GitHub (pinned to 2e990059ce)