grpc/grpc-java · error · IllegalArgumentException

CelMatcher must have expr_match

Error message

CelMatcher must have expr_match

What it means

CelStateMatcher.getMatcher() unpacks the TypedExtensionConfig's typed_config as an xDS CelMatcher proto and requires the expr_match field to be set. A CelMatcher proto without expr_match carries no CEL expression at all, so no matcher can be built. The factory rejects such configs with IllegalArgumentException.

Source

Thrown at xds/src/main/java/io/grpc/xds/internal/matcher/CelStateMatcher.java:57

      return compiledEndpoint.match(value);
    } catch (CelEvaluationException e) {
      return false;
    }
  }

  @Override
  public Class<?> inputType() {
    return GrpcCelEnvironment.class;
  }

  static final class Provider implements MatcherProvider {
    @Override
    public CelStateMatcher getMatcher(TypedExtensionConfig config) {
      try {
        com.github.xds.type.matcher.v3.CelMatcher celProto = config.getTypedConfig()
            .unpack(com.github.xds.type.matcher.v3.CelMatcher.class);
        if (!celProto.hasExprMatch()) {
          throw new IllegalArgumentException("CelMatcher must have expr_match");
        }
        CelExpression expr = celProto.getExprMatch();
        if (!expr.hasCelExprChecked()) {
          throw new IllegalArgumentException("CelMatcher must have cel_expr_checked");
        }
        CelAbstractSyntaxTree ast = 
            CelProtoAbstractSyntaxTree.fromCheckedExpr(
                expr.getCelExprChecked()).getAst();
        CelMatcher compiled = CelMatcher.compile(ast);
        
        return new CelStateMatcher(compiled);
      } catch (Exception e) {
        throw new IllegalArgumentException("Invalid CelMatcher config", e);
      }
    }

    @Override
    public String typeUrl() {

View on GitHub (pinned to 64daddc1f3)

Solutions

  1. Populate expr_match in the CelMatcher proto before sending the config (proto.hasExprMatch() must be true).
  2. Validate the extension config on the control plane side prior to xDS delivery.
  3. Catch IllegalArgumentException from getMatcher() and reject the whole config with an NACK / clearer error.

Example fix

// before
CelMatcher.newBuilder().build(); // expr_match missing
// after
CelMatcher.newBuilder()
    .setExprMatch(CelExpression.newBuilder().setCelExprChecked(checkedExpr))
    .build();
Defensive patterns

Strategy: validation

Validate before calling

CelMatcherProto.CelMatcher celProto =
    config.getTypedConfig().unpack(CelMatcherProto.CelMatcher.class);
if (!celProto.hasExprMatch()) throw new IllegalArgumentException("expr_match required");

Type guard

boolean hasExprMatch(TypedExtensionConfig config) {
  return config.getTypedConfig().is(CelMatcherProto.CelMatcher.class)
      && unpackSafe(config).hasExprMatch();
}

Try / catch

try { return factory.getMatcher(config); }
catch (IllegalArgumentException e) { nackConfig(config, "expr_match missing: " + e.getMessage()); return null; }

Prevention

When it happens

Trigger: An xDS TypedExtensionConfig whose typed_config is type.googleapis.com/xds.type.matcher.v3.CelMatcher but with expr_match unset (oneof empty) reaches getMatcher().

Common situations: Control plane emitting CelMatcher protos with only defaults populated; hand-written test fixtures forgetting to call setExprMatch(); proto field name changes across xDS type versions.

Understand the failure class

Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.

Related errors


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