grpc/grpc-java · error · IllegalArgumentException

OnMatch must have either matcher or action

Error message

OnMatch must have either matcher or action

What it means

OnMatch is constructed from an xDS proto route's on_match field, which must define exactly one of: a nested matcher tree or a terminal action. If the proto sets neither, the constructor throws this IllegalArgumentException because the OnMatch object would have no behavior to apply when the parent matcher matches.

Solutions

  1. Fix the xDS config so on_match sets either a nested matcher (match_tree) or an action with a supported typed_config
  2. Validate the route proto server-side before sending: check hasMatcher() || hasAction() for every on_match
  3. Wrap xDS config parsing in try-catch for IllegalArgumentException and reject/skip the offending route with a clear log message

Example fix

// before: on_match with neither matcher nor action
on_match: {}
// after
on_match:
  action:
    name: route_to_backend
    typed_config:
      '@type': type.googleapis.com/grpc.intent.RouteAction
Defensive patterns

Strategy: validation

Validate before calling

// reject before construction
if (!onMatchProto.hasMatcher() && onMatchProto.getAction().getTypedConfig().getTypeUrl().isEmpty()) {
  throw new IllegalArgumentException("on_match must set matcher or action");
}

Try / catch

try { OnMatch onMatch = new OnMatch(proto, actionValidator); } catch (IllegalArgumentException e) { log.warn("Skipping invalid on_match: " + e.getMessage()); return null; }

Prevention

When it happens

Trigger: Building an OnMatch from a Matcher.OnMatch proto where hasMatcher() is false and getAction() has no typed config set — e.g. a route or virtual host config where on_match is present but empty, or was stripped of both its matcher sub-message and its action during config generation.

Common situations: Malformed xDS route configurations from a management server (envoy-style route tables missing the recursive matcher or action); config conversion tools that emit an empty on_match placeholder; hand-written JSON/yaml xDS configs missing the matcher block.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


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

Appendix: source

Thrown at xds/src/main/java/io/grpc/xds/internal/matcher/OnMatch.java:45

final class OnMatch {
  @Nullable private final UnifiedMatcher nestedMatcher;
  @Nullable private final TypedExtensionConfig action;
  final boolean keepMatching;
  
  OnMatch(Matcher.OnMatch proto, Predicate<String> actionValidator) {
    this.keepMatching = proto.getKeepMatching();
    if (proto.hasMatcher()) {
      this.nestedMatcher = UnifiedMatcher.fromProto(proto.getMatcher(), actionValidator);
      this.action = null;
    } else if (proto.hasAction()) {
      this.nestedMatcher = null;
      this.action = proto.getAction();
      String typeUrl = this.action.getTypedConfig().getTypeUrl();
      if (!actionValidator.test(typeUrl)) {
        throw new IllegalArgumentException("Unsupported action type: " + typeUrl);
      }
    } else {
      throw new IllegalArgumentException("OnMatch must have either matcher or action");
    }
  }
  
  MatchResult evaluate(MatchContext context) {
    if (nestedMatcher != null) {
      return nestedMatcher.match(context);
    }
    return MatchResult.create(action);
  }
}

View on GitHub (pinned to 64daddc1f3)