grpc/grpc-java · error · IllegalArgumentException

SinglePredicate must have input

Error message

SinglePredicate must have input

What it means

A SinglePredicate pairs a MatchInput (the value source) with a Matcher (the test applied to that value). The input field is mandatory; if the proto lacks it, SinglePredicateEvaluator throws this IllegalArgumentException because there is nothing to evaluate against.

Source

Thrown at xds/src/main/java/io/grpc/xds/internal/matcher/PredicateEvaluator.java:52

        return new OrMatcherEvaluator(proto.getOrMatcher());
      case AND_MATCHER:
        return new AndMatcherEvaluator(proto.getAndMatcher());
      case NOT_MATCHER:
        return new NotMatcherEvaluator(proto.getNotMatcher());
      case MATCHTYPE_NOT_SET:
      default:
        throw new IllegalArgumentException(
            "Predicate must have one of: single_predicate, or_matcher, and_matcher, not_matcher");
    }
  }

  private static final class SinglePredicateEvaluator extends PredicateEvaluator {
    private final MatchInput input;
    private final Matcher matcher;
    
    SinglePredicateEvaluator(Predicate.SinglePredicate proto) {
      if (!proto.hasInput()) {
        throw new IllegalArgumentException("SinglePredicate must have input");
      }
      this.input = UnifiedMatcher.resolveInput(proto.getInput());
      
      if (proto.hasValueMatch()) {
        Matchers.StringMatcher stringMatcher =
            MatcherParser.parseStringMatcher(proto.getValueMatch());
        this.matcher = new StringMatcherAdapter(stringMatcher);
      } else if (proto.hasCustomMatch()) {
        TypedExtensionConfig customConfig = proto.getCustomMatch();
        MatcherProvider provider = MatcherRegistry.getDefaultRegistry()
            .getMatcherProvider(customConfig.getTypedConfig().getTypeUrl());
        if (provider == null) {
          throw new IllegalArgumentException("Unsupported custom_match matcher: " 
              + customConfig.getTypedConfig().getTypeUrl());
        }
        this.matcher = provider.getMatcher(customConfig);
      } else {
        throw new IllegalArgumentException(

View on GitHub (pinned to 64daddc1f3)

Solutions

  1. Set the input field (a TypedExtensionConfig identifying the MatchInput) on every SinglePredicate
  2. Check proto.hasInput() during config validation before parsing the matcher tree
  3. Update the management server/config template so input is always emitted alongside value_match/custom_match

Example fix

// before
single_predicate:
  value_match:
    exact: my-header-value
// after
single_predicate:
  input:
    typed_config:
      '@type': type.googleapis.com/grpc.xds.Input.MyHeaderInput
  value_match:
    exact: my-header-value
Defensive patterns

Strategy: validation

Validate before calling

if (!singlePredicate.hasInput()) {
  throw new IllegalArgumentException("single_predicate.input is required");
}

Try / catch

try { new PredicateEvaluator.SinglePredicateEvaluator(proto); } catch (IllegalArgumentException e) { log.warn("Dropping predicate: " + e.getMessage()); }

Prevention

When it happens

Trigger: Constructing a SinglePredicateEvaluator from a Predicate.SinglePredicate proto where hasInput() is false — e.g. a value_match or custom_match was configured but the input TypedExtensionConfig was omitted.

Common situations: xDS matcher configs where the input extension block is missing or renamed; config migration dropping the input field; hand-authored matcher trees that only specify the value condition.

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/61cfef8bbb7f4090. Report an issue: GitHub.