{"record":{"id":"9ca1d22f5b81ff30","repo":"languagetool-org/languagetool","slug":"missing-key-key","errorCode":null,"errorMessage":"Missing key '${key}'","messagePattern":"Missing key '(.+?)'","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"languagetool-core/src/main/java/org/languagetool/rules/patterns/RuleFilter.java","lineNumber":70,"sourceCode":"  @Nullable\n  public abstract RuleMatch acceptRuleMatch(RuleMatch match, Map<String, String> arguments, int patternTokenPos, AnalyzedTokenReadings[] patternTokens, List<Integer> tokenPositions) throws IOException;\n\n  /** @since 3.2 */\n  public boolean matches(Map<String, String> arguments, AnalyzedTokenReadings[] patternTokens, int firstMatchToken, List<Integer> tokenPositions) throws IOException {\n    RuleMatch fakeMatch = new RuleMatch(new FakeRule(), null, 0, 1, \"(internal rule)\");\n    return acceptRuleMatch(fakeMatch, arguments, firstMatchToken, patternTokens, tokenPositions) != null;\n  }\n\n  private static class FakeRule extends Rule {\n    @Override public String getId() { return \"FAKE-RULE-FOR-FILTER\"; }\n    @Override public String getDescription() { return \"<none>\"; }\n    @Override public RuleMatch[] match(AnalyzedSentence sentence) throws IOException { return RuleMatch.EMPTY_ARRAY; }\n  }\n\n  protected String getRequired(String key, Map<String, String> map) {\n    String result = map.get(key);\n    if (result == null) {\n      throw new IllegalArgumentException(\"Missing key '\" + key + \"'\");\n    }\n    return result;\n  }\n\n  protected String getOptional(String key, Map<String, String> map) {\n    return map.get(key);\n  }\n\n  protected String getOptional(String key, Map<String, String> map, String defaultValue) {\n    String value = map.get(key);\n    if (value == null) {\n      return defaultValue;\n    }\n    return value;\n  }\n\n  protected int getPosition(String fromStr, AnalyzedTokenReadings[] patternTokens, RuleMatch match) {\n    int i;","sourceCodeStart":52,"sourceCodeEnd":88,"githubUrl":"https://github.com/languagetool-org/languagetool/blob/2e990059ce67d5e2a0f7f7ca5d31160c6709df4b/languagetool-core/src/main/java/org/languagetool/rules/patterns/RuleFilter.java#L52-L88","documentation":"RuleFilter.getRequired() is a helper for custom RuleFilter implementations in LanguageTool. It looks up a key in the filter's argument map (the key='value' attributes of the <filter> element / token properties in the rule XML). When the map has no entry for the requested key it throws IllegalArgumentException, because the filter cannot do its job without that value.","triggerScenarios":"A RuleFilter subclass calls getRequired(\"someKey\", args) but the rule XML that references the filter does not define the matching attribute, or the attribute name in XML and the key string in Java differ in case or spelling.","commonSituations":"Renaming an XML attribute in a grammar/rule file without updating the filter class (or vice versa); copying a filter element from another rule and forgetting to add a required attribute; typos like 'postag' vs 'posTag' in the map key.","solutions":["Add the missing attribute (key='value') to the filter/token element in the rule XML so it matches the key passed to getRequired","Check exact spelling and case of the key in both the XML file and the getRequired call; align them","Temporarily log the full args map inside the filter to see which keys actually arrive and fix the mismatch","If the key is genuinely optional, switch the call to getOptional(key, map) and handle null"],"exampleFix":"// before (XML)\n<token regexp=\"yes\">...</token>\n// after (XML)\n<token regexp=\"yes\" postag_regexp=\"yes\" postag=\"NN.*\"/>","handlingStrategy":"validation","validationCode":"Set<String> required = Set.of(\"postag\", \"position\");\nSet<String> provided = args.keySet();\njava.util.List<String> missing = new java.util.ArrayList<>(required);\nmissing.removeAll(provided);\nif (!missing.isEmpty()) throw new IllegalArgumentException(\"Filter args missing keys: \" + missing);","typeGuard":"if (args != null && args.containsKey(key)) { /* safe to getRequired */ }","tryCatchPattern":"try {\n  String value = getRequired(key, args);\n} catch (IllegalArgumentException e) {\n  throw new RuleFilterInitializationException(\"Rule \" + ruleId + \" misconfigured: \" + e.getMessage(), e);\n}","preventionTips":["Keep key names in the rule XML and getRequired calls in a shared constant list","Test each rule XML that uses a filter in a unit test so a missing attribute fails at build time","Log the full args map when debugging filter issues","Use getOptional only for keys that are genuinely optional"],"tags":["java","languagetool","rule-filter","configuration"],"backgroundTag":"missing-required-argument","analyzedSha":"2e990059ce67d5e2a0f7f7ca5d31160c6709df4b","analyzedAt":"2026-09-06T09:20:17.015Z","contentChangedAt":"2026-09-06T09:20:17.015Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}