languagetool-org/languagetool · error · SAXException
Only backward references in match elements are possible, tri
Error message
Only backward references in match elements are possible, tried to specify token ${refNumber}
Line: ${pLocator.getLineNumber()}, column: ${pLocator.getColumnNumber()}. What it means
XMLRuleHandler.checkRefNumber throws this SAXException when a <match no='N'> reference points to a token at or after the current pattern position. References in match elements may only be backward (to earlier tokens), because the token being matched cannot reference itself or a future token. The error names the offending token number and the XML location.
Source
Thrown at languagetool-core/src/main/java/org/languagetool/rules/patterns/XMLRuleHandler.java:433
elements.append(refNumber);
}
}
private void checkNumber(Attributes attrs) throws SAXException {
if (StringTools.isEmpty(attrs.getValue("no"))) {
throw new SAXException("References cannot be empty: " + "\n Line: "
+ pLocator.getLineNumber() + ", column: "
+ pLocator.getColumnNumber() + ".");
} else if (Integer.parseInt(attrs.getValue("no")) < 1 && regex.length() == 0) {
throw new SAXException("References must be larger than 0: "
+ attrs.getValue("no") + "\n Line: " + pLocator.getLineNumber()
+ ", column: " + pLocator.getColumnNumber() + ".");
}
}
private void checkRefNumber(int refNumber) throws SAXException {
if (refNumber > patternTokens.size()) {
throw new SAXException("Only backward references in match elements are possible, tried to specify token "
+ refNumber + "\n" + "Line: " + pLocator.getLineNumber()
+ ", column: " + pLocator.getColumnNumber() + ".");
}
}
protected void setExceptions(Attributes attrs) {
inException = true;
exceptions = new StringBuilder();
resetException();
exceptionStringNegation = YES.equals(attrs.getValue(NEGATE));
exceptionValidNext = "next".equals(attrs.getValue(SCOPE));
exceptionValidPrev = "previous".equals(attrs.getValue(SCOPE));
exceptionStringInflected = YES.equals(attrs.getValue(INFLECTED));
if (attrs.getValue(POSTAG) != null) {
exceptionPosToken = StringInterner.intern(attrs.getValue(POSTAG));
exceptionPosRegExp = YES.equals(attrs.getValue(POSTAG_REGEXP));View on GitHub (pinned to 2e990059ce)
Solutions
- Lower the 'no' value so it refers to an earlier token in the pattern
- Move the <match> element after the token it references, or restructure the rule
- Re-count token positions (1-based, counting only preceding pattern tokens) after editing the rule
Example fix
// before (first token cannot reference token 2) <token>foo</token><match no="2"/> // after <token>foo</token><match no="1"/>
Defensive patterns
Strategy: validation
Validate before calling
// While building rules programmatically, track current token position
int currentPosition = /* index of token being defined */;
int refNumber = parseNo(matchElement);
if (refNumber > currentPosition) {
throw new IllegalArgumentException("Forward reference no=" + refNumber + " at token " + currentPosition);
} Type guard
boolean isBackwardReference(int refNumber, int tokensDefinedSoFar) {
return refNumber >= 1 && refNumber <= tokensDefinedSoFar;
} Try / catch
try {
loader.getRules(is, filename);
} catch (SAXException e) {
if (e.getMessage().startsWith("Only backward references")) {
log.error("Renumber match references; they may only point to earlier tokens", e);
} else throw e;
} Prevention
- Only reference tokens defined earlier in the pattern
- Renumber all <match no> values whenever tokens are reordered or inserted
- Add a custom lint that checks reference positions during rule CI
When it happens
Trigger: Parsing rule XML where the 'no' attribute exceeds patternTokens.size() at parse time, e.g. <match no="2"/> placed as the first token, or referencing a token not yet defined in the pattern.
Common situations: Reordering tokens after writing matches and forgetting to renumber references; authors trying forward references; rules copied with offsets that no longer line up.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- References cannot be empty: Line: ${pLocator.getLineNumber
- References must be larger than 0: ${attrs.getValue("no")} L
- You cannot set both 'chunk' and 'chunk_re' for + id
- Please set min and max attributes on the first token in the
- <antipattern>s can only contain <example>s without errors (i
AI-assisted analysis of languagetool-org/languagetool@2e990059ce (2026-09-06).
Data as JSON: /api/errors/e45e4dee847c2fa8.
Report an issue: GitHub.