languagetool-org/languagetool · error · SAXException

You cannot set both 'chunk' and 'chunk_re' for + id

Error message

You cannot set both 'chunk' and 'chunk_re' for + id

What it means

XMLRuleHandler throws this SAXException when a token element specifies both a 'chunk' attribute and a 'chunk_re' attribute. 'chunk' matches a chunk tag literally while 'chunk_re' treats it as a regular expression; setting both is ambiguous, so rule loading fails with the rule id in the message. Pick exactly one form per token.

Source

Thrown at languagetool-core/src/main/java/org/languagetool/rules/patterns/XMLRuleHandler.java:532

    tokenNegated = YES.equals(attrs.getValue(NEGATE));
    tokenInflected = YES.equals(attrs.getValue(INFLECTED));
    if (attrs.getValue(SKIP) != null) {
      skipPos = Integer.parseInt(attrs.getValue(SKIP));
    }
    if (attrs.getValue(MIN) != null) {
      minOccurrence = Integer.parseInt(attrs.getValue(MIN));
    }
    if (attrs.getValue(MAX) != null) {
      maxOccurrence = Integer.parseInt(attrs.getValue(MAX));
    }
    elements = new StringBuilder();
    if (attrs.getValue(POSTAG) != null) {
      posToken = StringInterner.intern(attrs.getValue(POSTAG));
      posRegExp = YES.equals(attrs.getValue(POSTAG_REGEXP));
      posNegation = YES.equals(attrs.getValue(NEGATE_POS));
    }
    if (attrs.getValue(CHUNKTAG) != null && attrs.getValue(CHUNKTAG_REGEXP) != null) {
      throw new SAXException("You cannot set both 'chunk' and 'chunk_re' for " + id);
    }
    if (attrs.getValue(CHUNKTAG) != null) {
      chunkTag = new ChunkTag(StringInterner.intern(attrs.getValue(CHUNKTAG)));
    } else if (attrs.getValue(CHUNKTAG_REGEXP) != null) {
      chunkTag = new ChunkTag(StringInterner.intern(attrs.getValue(CHUNKTAG_REGEXP)), true);
    }
    regExpression = YES.equals(attrs.getValue(REGEXP));
    if (attrs.getValue(SPACEBEFORE) != null) {
      tokenSpaceBefore = YES.equals(attrs.getValue(SPACEBEFORE));
      tokenSpaceBeforeSet = !IGNORE.equals(attrs.getValue(SPACEBEFORE));
    }
    if (!inAndGroup && !inOrGroup) {
      tokenCounter++;
    }
    if (attrs.getValue(CASE_SENSITIVE) != null) {
      tokenLevelCaseSet = true;
      tokenLevelCaseSensitive = YES.equals(attrs.getValue(CASE_SENSITIVE));
    } else {

View on GitHub (pinned to 2e990059ce)

Solutions

  1. Delete one of the two attributes — keep 'chunk' for literal matching or 'chunk_re' for regex
  2. If you need alternation, express it in chunk_re (e.g. chunk_re="NP|PP") rather than combining attributes
  3. Add a schema/lint check in CI for tokens carrying both attributes

Example fix

// before
<token chunk="NP" chunk_re="N.*"/>
// after
<token chunk_re="N.*"/>
Defensive patterns

Strategy: validation

Validate before calling

// Pre-parse check
NodeList tokens = doc.getElementsByTagName("token");
for (int i = 0; i < tokens.getLength(); i++) {
  Element t = (Element) tokens.item(i);
  if (t.hasAttribute("chunk") && t.hasAttribute("chunk_re")) {
    throw new IllegalArgumentException("Token " + i + " sets both chunk and chunk_re");
  }
}

Try / catch

try {
  loader.getRules(is, filename);
} catch (SAXException e) {
  if (e.getMessage().startsWith("You cannot set both 'chunk' and 'chunk_re'")) {
    log.error("Keep only one of chunk/chunk_re per token", e);
  } else throw e;
}

Prevention

When it happens

Trigger: Parsing a token like <token chunk="NP" chunk_re="N.*"/> in setToken — both CHUNKTAG and CHUNKTAG_REGEXP attribute values are non-null and the handler throws before building the ChunkTag.

Common situations: Migrating rules where one attribute was added without removing the other; copy-paste from two rule examples; templated rule generation merging both options.

Related errors


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