languagetool-org/languagetool · error · RuntimeException
Duplicate key '${key}'
Error message
Duplicate key '${key}' What it means
RuleFilterEvaluator.getResolvedArguments throws this when two filter arguments resolve to the same key name, meaning the rule declared duplicate argument names for a filter. The result map is built key-by-key from the args attribute, and duplicates would silently overwrite each other, so the evaluator fails fast. It usually reflects a typo or copy-paste in the 'args' attribute of a <filter> element.
Source
Thrown at languagetool-core/src/main/java/org/languagetool/rules/patterns/RuleFilterEvaluator.java:73
for (String arg : arguments) {
int delimPos = arg.indexOf(':');
if (delimPos == -1) {
throw new RuntimeException("Invalid syntax for key/value, expected 'key:value', got: '" + arg + "'");
}
String key = arg.substring(0, delimPos);
String val = arg.substring(delimPos + 1);
if (val.startsWith("\\")) {
int refNumber = Integer.parseInt(val.replace("\\", ""));
if (refNumber > tokenPositions.size()) {
throw new RuntimeException("Your reference number " + refNumber + " is bigger than the number of tokens: " + tokenPositions.size());
}
int correctedRef = getSkipCorrectedReference(tokenPositions, refNumber);
if (correctedRef >= patternTokens.length) {
throw new RuntimeException("Your reference number " + refNumber +
" is bigger than number of matching tokens: " + patternTokens.length);
}
if (result.containsKey(key)) {
throw new RuntimeException("Duplicate key '" + key + "'");
}
result.put(key, patternTokens[correctedRef].getToken());
} else {
result.put(key, val);
}
}
return result;
}
// when there's a 'skip', we need to adapt the reference number
private int getSkipCorrectedReference(List<Integer> tokenPositions, int refNumber) {
int correctedRef = 0;
int i = 0;
for (int tokenPosition : tokenPositions) {
if (i++ >= refNumber) {
break;
}
correctedRef += tokenPosition;View on GitHub (pinned to 2e990059ce)
Solutions
- Edit the filter's args attribute so every key is unique
- Rename the duplicate argument and update the filter Java class to use the new parameter name
- Validate rule XML in CI (LanguageTool's rule validation / tests) to catch duplicate keys early
Example fix
// before <filter class="..." args="no:1 no:2"/> // after <filter class="..." args="no:1 postag:2"/>
Defensive patterns
Strategy: validation
Validate before calling
Set<String> seen = new HashSet<>();
for (String pair : argsString.split(",")) {
String key = pair.split(":")[0].trim().toLowerCase(Locale.ROOT);
if (!seen.add(key)) throw new IllegalArgumentException("Duplicate filter arg key: " + key);
} Try / catch
try {
result = evaluator.getResolvedArguments(filterId, args, matches, patternTokens);
} catch (RuntimeException e) {
if (e.getMessage().startsWith("Duplicate key")) {
log.error("Fix duplicate args key in rule XML", e);
} else throw e;
} Prevention
- Ensure each key in a filter's args attribute is unique
- Validate args strings programmatically before rule deployment
- Use distinct, descriptive argument names in filter classes
When it happens
Trigger: A <filter args='word:1 word:2'/> or args string containing the same key twice (e.g. 'no:1 No:2' after normalization) is evaluated; getResolvedArguments checks result.containsKey(key) before each put.
Common situations: Copy-pasting filter argument lists, renaming one argument but leaving the old one in place, generating args strings programmatically with repeated keys, case-insensitive key collisions.
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
- Your reference number ${refNumber} is bigger than number of
- References cannot be empty: Line: ${pLocator.getLineNumber
- References must be larger than 0: ${attrs.getValue("no")} L
- Only backward references in match elements are possible, tri
- You cannot set both 'chunk' and 'chunk_re' for + id
AI-assisted analysis of languagetool-org/languagetool@2e990059ce (2026-09-06).
Data as JSON: /api/errors/bebec47bd0dc36ac.
Report an issue: GitHub.