grpc/grpc-java · error · IllegalArgumentException

StringMatcher expected a String input, but received

Error message

StringMatcher expected a String input, but received: ${value class name}

What it means

The adapter exposing StringMatcher as a generic Matcher only accepts String values. If evaluate() hands it a non-String (non-null) value, it throws this IllegalArgumentException naming the actual received class, since StringMatcher.matches only understands strings.

Solutions

  1. Fix the MatchInput so it outputs a String (or its outputType() declaration matches the matcher's expected String input)
  2. Replace value_match with a custom_match whose matcher accepts the input's actual type
  3. Wrap custom inputs so they stringify their output before reaching StringMatcher

Example fix

// before
public Object evaluate(MatchContext ctx) {
  return ctx.request().headerCount(); // Integer into StringMatcher
}
// after
public Object evaluate(MatchContext ctx) {
  return String.valueOf(ctx.request().headerCount());
}
Defensive patterns

Strategy: type-guard

Validate before calling

if (matcher.inputType() != String.class && !(value instanceof String)) {
  throw new IllegalStateException("StringMatcher fed non-String value");
}

Type guard

static boolean isStringValue(Object v) { return v instanceof String; }

Try / catch

try { boolean r = evaluator.evaluate(ctx); } catch (IllegalArgumentException e) { log.error("Matcher input type error: " + e.getMessage()); return MatchResult.noMatch(); }

Prevention

When it happens

Trigger: Running a matcher tree where a SinglePredicate's input produces a non-String value (e.g. an integer or boolean output from a custom MatchInput) but the matcher is a StringMatcherAdapter wrapping a StringMatcher; type checks at construction passed or were bypassed.

Common situations: Custom MatchInput implementations whose outputType() claim doesn't match the produced runtime type; config where value_match is combined with a binary/numeric input; reflection or dynamic input resolution returning unexpected types.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


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

Appendix: source

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

      return matcher.match(input.apply(context));
    }
    


    private static final class StringMatcherAdapter implements Matcher {
      private final Matchers.StringMatcher stringMatcher;

      StringMatcherAdapter(Matchers.StringMatcher stringMatcher) {
        this.stringMatcher = stringMatcher;
      }

      @Override
      public boolean match(Object value) {
        if (value == null) {
          return false;
        }
        if (!(value instanceof String)) {
          throw new IllegalArgumentException(
              "StringMatcher expected a String input, but received: " 
              + value.getClass().getName());
        }
        return stringMatcher.matches((String) value);
      }

      @Override
      public Class<?> inputType() {
        return String.class;
      }
    }
  }
  
  private static final class OrMatcherEvaluator extends PredicateEvaluator {
    private final List<PredicateEvaluator> evaluators;
    
    OrMatcherEvaluator(Predicate.PredicateList proto) {
      if (proto.getPredicateCount() < 2) {

View on GitHub (pinned to 64daddc1f3)