languagetool-org/languagetool · error · RuntimeException

Invalid syntax for key/value, expected 'key:value', got: '${

Error message

Invalid syntax for key/value, expected 'key:value', got: '${arg}'

What it means

RuleFilterEvaluator.getResolvedArguments splits the filter attribute's argument string on whitespace and requires each argument to be of the form key:value. If an argument contains no colon, it throws this RuntimeException. The syntax of filter arguments in the rule XML is invalid.

Source

Thrown at languagetool-core/src/main/java/org/languagetool/rules/patterns/RuleFilterEvaluator.java:58

    this.filter = filter;
  }

  @Nullable
  public RuleMatch runFilter(String filterArgs, RuleMatch ruleMatch, AnalyzedTokenReadings[] patternTokens, int patternTokenPos, List<Integer> tokenPositions) throws IOException {
    Map<String,String> args = getResolvedArguments(filterArgs, patternTokens, patternTokenPos, tokenPositions);
    return filter.acceptRuleMatch(ruleMatch, args, patternTokenPos, patternTokens, tokenPositions);
  }

  /**
   * Resolves the backref arguments, e.g. replaces {@code \1} by the value of the first token in the pattern.
   */
  public Map<String,String> getResolvedArguments(String filterArgs, AnalyzedTokenReadings[] patternTokens, int patternTokenPos, List<Integer> tokenPositions) {
    Map<String,String> result = new HashMap<>();
    String[] arguments = WHITESPACE.split(filterArgs);
    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 {

View on GitHub (pinned to 2e990059ce)

Solutions

  1. Give every whitespace-separated argument a key:value form, e.g. `no:1 case_sensitive:true`.
  2. Replace any other separator (=, space-only key) with a colon.
  3. Count tokens: every token in the filter attribute must contain at least one ':'; remove stray tokens.
  4. If you intentionally need a value with spaces, this API cannot express it — restructure the argument or quote-free reformulate it.

Example fix

// before
String args = "no:1 case_sensitive";
// after
String args = "no:1 case_sensitive:true";
Defensive patterns

Strategy: validation

Validate before calling

for (String arg : filterArgs.split("\\s+")) {
  if (!arg.contains(":")) {
    throw new IllegalArgumentException("Filter argument must be key:value: " + arg);
  }
}

Try / catch

try {
  Map<String,String> resolved = evaluator.getResolvedArguments(filterArgs, tokens, pos, positions);
} catch (RuntimeException e) {
  if (e.getMessage().startsWith("Invalid syntax for key/value")) {
    throw new IllegalArgumentException("Bad filter args: " + filterArgs, e);
  }
  throw e;
}

Prevention

When it happens

Trigger: A filterArgs string passed to getResolvedArguments (directly or via evaluating a rule's <filter> element) contains a whitespace-separated token without a colon, e.g. 'no:12 yes' or 'case_sensitive' instead of 'case_sensitive:true'.

Common situations: Hand-editing rule XML and forgetting the value after the key; using '=' or '->' instead of ':' as the separator; extra stray token from a bad line wrap; copy-paste that dropped the ':value' part.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


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