{"record":{"id":"59fb0bc058d39801","repo":"grpc/grpc-java","slug":"matcherlist-must-contain-at-least-one-fieldmatcher","errorCode":null,"errorMessage":"MatcherList must contain at least one FieldMatcher","messagePattern":"MatcherList must contain at least one FieldMatcher","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"xds/src/main/java/io/grpc/xds/internal/matcher/MatcherList.java","lineNumber":34,"sourceCode":"\npackage io.grpc.xds.internal.matcher;\n\nimport com.github.xds.core.v3.TypedExtensionConfig;\nimport com.github.xds.type.matcher.v3.Matcher;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.function.Predicate;\nimport javax.annotation.Nullable;\n\nfinal class MatcherList extends UnifiedMatcher {\n  private final List<FieldMatcher> matchers;\n  @Nullable \n  private final OnMatch onNoMatch;\n\n  MatcherList(Matcher.MatcherList proto, @Nullable Matcher.OnMatch onNoMatchProto,\n      Predicate<String> actionValidator) {\n    if (proto.getMatchersCount() == 0) {\n      throw new IllegalArgumentException(\"MatcherList must contain at least one FieldMatcher\");\n    }\n    this.matchers = new ArrayList<>(proto.getMatchersCount());\n    for (Matcher.MatcherList.FieldMatcher fm : proto.getMatchersList()) {\n      matchers.add(new FieldMatcher(fm, actionValidator));\n    }\n    if (onNoMatchProto != null) {\n      this.onNoMatch = new OnMatch(onNoMatchProto, actionValidator);\n    } else {\n      this.onNoMatch = null;\n    }\n  }\n\n  @Override\n  MatchResult match(MatchContext context) {\n    List<TypedExtensionConfig> accumulated = new ArrayList<>();\n    for (FieldMatcher matcher : matchers) {\n      if (matcher.matches(context)) {\n        MatchResult result = matcher.onMatch.evaluate(context);","sourceCodeStart":16,"sourceCodeEnd":52,"githubUrl":"https://github.com/grpc/grpc-java/blob/64daddc1f3d1975670f769f3e97bde8b2ba32d25/xds/src/main/java/io/grpc/xds/internal/matcher/MatcherList.java#L16-L52","documentation":"A MatcherList must contain at least one FieldMatcher; an empty list can never match anything, so the constructor rejects it eagerly. This enforces the xDS/Envoy matcher API constraint that a list-based matcher defines at least one predicate.","triggerScenarios":"Constructing MatcherList from a Matcher.MatcherList proto whose matchers list is empty (matchers_count == 0).","commonSituations":"Control plane emits a matcher config with an empty matchers array, often after stripping all entries due to a filtering bug or when a template was rendered with no values.","solutions":["Add at least one FieldMatcher to the MatcherList config.","Validate on the management server that matchers is non-empty before sending the config.","If the list may legitimately be empty, restructure to use on_no_match only or drop the matcher entirely."],"exampleFix":"// before\n{\"matcher_list\": {\"matchers\": []}}\n// after\n{\"matcher_list\": {\"matchers\": [{\"predicate\": {...}, \"on_match\": {...}}]}}","handlingStrategy":"validation","validationCode":"if (proto.getMatchersCount() == 0) {\n  throw new IllegalArgumentException(\"MatcherList proto has no matchers; refusing to build\");\n}","typeGuard":"boolean usableMatcherList(io.envoyproxy.envoy.type.matcher.v3.Matcher.MatcherList proto) {\n  return proto.getMatchersCount() > 0;\n}","tryCatchPattern":"try {\n  matcher = new MatcherList(proto, onNoMatch, validator);\n} catch (IllegalArgumentException e) {\n  logger.warn(\"rejecting empty MatcherList config: \" + e.getMessage());\n  throw new StatusRuntimeException(Status.INVALID_ARGUMENT.withDescription(e.getMessage()));\n}","preventionTips":["Reject empty matchers arrays at config-generation time","Require at least one FieldMatcher in templates","Surface control-plane validation errors instead of emitting empty lists"],"tags":["xds","matcher","config-validation"],"backgroundTag":"empty-required-field","analyzedSha":"64daddc1f3d1975670f769f3e97bde8b2ba32d25","analyzedAt":"2026-09-08T06:14:57.704Z","contentChangedAt":"2026-09-08T06:14:57.704Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}