grpc/grpc-java · error · IllegalArgumentException

MatcherList must contain at least one FieldMatcher

Error message

MatcherList must contain at least one FieldMatcher

What it means

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.

Solutions

  1. Add at least one FieldMatcher to the MatcherList config.
  2. Validate on the management server that matchers is non-empty before sending the config.
  3. If the list may legitimately be empty, restructure to use on_no_match only or drop the matcher entirely.

Example fix

// before
{"matcher_list": {"matchers": []}}
// after
{"matcher_list": {"matchers": [{"predicate": {...}, "on_match": {...}}]}}
Defensive patterns

Strategy: validation

Validate before calling

if (proto.getMatchersCount() == 0) {
  throw new IllegalArgumentException("MatcherList proto has no matchers; refusing to build");
}

Type guard

boolean usableMatcherList(io.envoyproxy.envoy.type.matcher.v3.Matcher.MatcherList proto) {
  return proto.getMatchersCount() > 0;
}

Try / catch

try {
  matcher = new MatcherList(proto, onNoMatch, validator);
} catch (IllegalArgumentException e) {
  logger.warn("rejecting empty MatcherList config: " + e.getMessage());
  throw new StatusRuntimeException(Status.INVALID_ARGUMENT.withDescription(e.getMessage()));
}

Prevention

When it happens

Trigger: Constructing MatcherList from a Matcher.MatcherList proto whose matchers list is empty (matchers_count == 0).

Common situations: 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.

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


AI-assisted analysis of grpc/grpc-java@64daddc1f3 (2026-09-08). Data as JSON: /api/errors/59fb0bc058d39801. Report an issue: GitHub.

Appendix: source

Thrown at xds/src/main/java/io/grpc/xds/internal/matcher/MatcherList.java:34

package io.grpc.xds.internal.matcher;

import com.github.xds.core.v3.TypedExtensionConfig;
import com.github.xds.type.matcher.v3.Matcher;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;
import javax.annotation.Nullable;

final class MatcherList extends UnifiedMatcher {
  private final List<FieldMatcher> matchers;
  @Nullable 
  private final OnMatch onNoMatch;

  MatcherList(Matcher.MatcherList proto, @Nullable Matcher.OnMatch onNoMatchProto,
      Predicate<String> actionValidator) {
    if (proto.getMatchersCount() == 0) {
      throw new IllegalArgumentException("MatcherList must contain at least one FieldMatcher");
    }
    this.matchers = new ArrayList<>(proto.getMatchersCount());
    for (Matcher.MatcherList.FieldMatcher fm : proto.getMatchersList()) {
      matchers.add(new FieldMatcher(fm, actionValidator));
    }
    if (onNoMatchProto != null) {
      this.onNoMatch = new OnMatch(onNoMatchProto, actionValidator);
    } else {
      this.onNoMatch = null;
    }
  }

  @Override
  MatchResult match(MatchContext context) {
    List<TypedExtensionConfig> accumulated = new ArrayList<>();
    for (FieldMatcher matcher : matchers) {
      if (matcher.matches(context)) {
        MatchResult result = matcher.onMatch.evaluate(context);

View on GitHub (pinned to 64daddc1f3)