languagetool-org/languagetool · error · RuntimeException

Cannot activate rule '

Error message

Cannot activate rule '

What it means

Every pattern rule must live inside a <category> element; the handler keeps the parsed category and throws this RuntimeException in prepareRule when it is null at rule creation time. Categories are how rules are grouped and toggled in the UI.

Source

Thrown at languagetool-core/src/main/java/org/languagetool/rules/patterns/PatternRuleHandler.java:905

    rule.setGoalSpecific(isGoalSpecific);
    if (inRuleGroup) {
      rule.setSubId(StringInterner.intern(Integer.toString(subId)));
    } else {
      rule.setSubId("1");
    }
    caseSensitive = false;
    for (Match m : suggestionMatches) {
      rule.addSuggestionMatch(m);
    }
    if (phrasePatternTokens.size() <= 1) {
      suggestionMatches.clear();
    }
    for (Match m : suggestionMatchesOutMsg) {
      rule.addSuggestionMatchOutMsg(m);
    }
    suggestionMatchesOutMsg.clear();
    if (category == null) {
      throw new RuntimeException("Cannot activate rule '" + id + "', it is outside of a <category>...</category>");
    }
    if (defaultOff) {
      rule.setDefaultOff();
    }
    if (defaultTempOff) {
      rule.setDefaultTempOff();
    }
    if (url != null && url.length() > 0) {
      try {
        String s = url.toString();
        rule.setUrl(internUrl(s));
      } catch (MalformedURLException e) {
        throw new RuntimeException("Could not parse URL for rule: " + rule + ": '" + url + "'", e);
      }
    } else if (urlForRuleGroup != null && urlForRuleGroup.length() > 0) {
      try {
        rule.setUrl(internUrl(urlForRuleGroup.toString()));
      } catch (MalformedURLException e) {

View on GitHub (pinned to 2e990059ce)

Solutions

  1. Wrap the rule (or rulegroup) in a <category> element with a name and id
  2. Copy the category element from the original file the rule came from
  3. For test XML fragments, add a minimal <category name="Test" id="TEST"> wrapper

Example fix

// before
<rule id="X" name="x">...</rule>
// after
<category id="MYCAT" name="My category">
  <rule id="X" name="x">...</rule>
</category>
Defensive patterns

Strategy: validation

Validate before calling

// Ensure every top-level rule/rulegroup is inside a category
NodeList rules = doc.getElementsByTagName("rule");
for (int i = 0; i < rules.getLength(); i++) {
  Node p = rules.item(i).getParentNode();
  boolean inCategory = false;
  while (p != null) { if ("category".equals(p.getNodeName())) { inCategory = true; break; } p = p.getParentNode(); }
  if (!inCategory) throw new IllegalStateException("rule outside <category>: " + ((Element) rules.item(i)).getAttribute("id"));
}

Try / catch

try { loader.parse(ruleXml, lang); } catch (RuntimeException e) { if (e.getMessage().contains("outside of a <category>")) { log.error("Wrap rule in a <category> element"); } throw e; }

Prevention

When it happens

Trigger: Parsing a rule XML where <rule> (or <rulegroup>) appears at top level without an enclosing <category>...</category>.

Common situations: Extracting a single rule into a standalone test XML without copying its category; concatenating rule files and dropping the category wrapper.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


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