grpc/grpc-java · error · IllegalArgumentException
MatcherTree exact_match_map must contain at least one entry
Error message
MatcherTree exact_match_map must contain at least one entry
What it means
If a MatcherTree specifies exact_match_map, the map must contain at least one entry; an empty exact-match map is a config error because the tree would have no keys to match against. The constructor validates the count eagerly.
Solutions
- Populate exact_match_map with at least one key -> on_match entry.
- Validate the map is non-empty on the management server before emitting the config.
- If the map can be empty, remove the exact_match_map field and provide a prefix_match_map or restructure the matcher.
Example fix
// before
{"matcher_tree": {"input": {...}, "exact_match_map": {"map": {}}}}
// after
{"matcher_tree": {"input": {...}, "exact_match_map": {"map": {"route-a": {"matcher": {...}}}}}} Defensive patterns
Strategy: validation
Validate before calling
if (treeProto.hasExactMatchMap() && treeProto.getExactMatchMap().getMapCount() == 0) {
throw new IllegalArgumentException("exact_match_map present but empty");
} Type guard
boolean hasNonEmptyExactMap(Matcher.MatcherTree proto) {
return !proto.hasExactMatchMap() || proto.getExactMatchMap().getMapCount() > 0;
} Try / catch
try {
matcherTree = new MatcherTree(proto, onNoMatch, validator);
} catch (IllegalArgumentException e) {
logger.warn("empty exact_match_map in config: " + e.getMessage());
throw e;
} Prevention
- Never emit an empty exact_match_map; omit the field instead
- Assert map non-empty after template rendering
- Validate configs before publish on the management server
When it happens
Trigger: Constructing MatcherTree from a proto with hasExactMatchMap() true but matchMap.getMapCount() == 0 (the map field set but empty).
Common situations: Templated config rendering with an empty map, or control-plane code setting exact_match_map without adding entries after filtering.
Understand the failure class
Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.
Related errors
- AndMatcher must have at least 2 predicates
- MatcherList must contain at least one FieldMatcher
- MatcherTree must have input
- MatcherTree prefix_match_map must contain at least one entry
- OrMatcher must have at least 2 predicates
AI-assisted analysis of grpc/grpc-java@64daddc1f3 (2026-09-08).
Data as JSON: /api/errors/f77f1799f0cfff16.
Report an issue: GitHub.
Appendix: source
Thrown at xds/src/main/java/io/grpc/xds/internal/matcher/MatcherTree.java:60
if (!proto.hasInput()) {
throw new IllegalArgumentException("MatcherTree must have input");
}
if (proto.getInput().getTypedConfig().getTypeUrl()
.equals(TYPE_URL_HTTP_ATTRIBUTES_CEL_INPUT)) {
throw new IllegalArgumentException(
"HttpAttributesCelMatchInput cannot be used with MatcherTree");
}
if (proto.hasCustomMatch()) {
throw new IllegalArgumentException("MatcherTree does not support custom_match");
}
this.input = UnifiedMatcher.resolveInput(proto.getInput());
if (proto.hasExactMatchMap()) {
Matcher.MatcherTree.MatchMap matchMap = proto.getExactMatchMap();
if (matchMap.getMapCount() == 0) {
throw new IllegalArgumentException(
"MatcherTree exact_match_map must contain at least one entry");
}
this.exactMatchMap = new HashMap<>();
for (Map.Entry<String, Matcher.OnMatch> entry :
matchMap.getMapMap().entrySet()) {
this.exactMatchMap.put(entry.getKey(),
new OnMatch(entry.getValue(), actionValidator));
}
this.prefixTrie = null;
} else if (proto.hasPrefixMatchMap()) {
Matcher.MatcherTree.MatchMap matchMap = proto.getPrefixMatchMap();
if (matchMap.getMapCount() == 0) {
throw new IllegalArgumentException(
"MatcherTree prefix_match_map must contain at least one entry");
}
this.prefixTrie = new PrefixTrie();
for (Map.Entry<String, Matcher.OnMatch> entry :
matchMap.getMapMap().entrySet()) {View on GitHub (pinned to 64daddc1f3)