grpc/grpc-java · error · IllegalArgumentException

Invalid CelMatcher config

Error message

Invalid CelMatcher config

What it means

getMatcher() wraps the whole unpack/validate/compile sequence in a catch-all that rethrows any failure as IllegalArgumentException("Invalid CelMatcher config", e). This is a generic factory-level wrapper: the original cause (unpack failure, missing fields, CEL type errors) is preserved as the cause chain. Any malformed CelMatcher typed_config ends up here.

Source

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

    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() {
      return TYPE_URL;
    }
  }
}

View on GitHub (pinned to 64daddc1f3)

Solutions

  1. Inspect the cause via e.getCause() to find the real problem (unpack error, missing field, or compile type error).
  2. Verify the TypedExtensionConfig's typeUrl matches TYPE_URL and that the Any payload is a well-formed CelMatcher proto.
  3. Confirm expr_match.cel_expr_checked is a BOOL-typed checked expression before sending the config.
  4. Catch IllegalArgumentException around getMatcher() and NACK the config with the root cause logged.

Example fix

// before
try { matcher = factory.getMatcher(config); } catch (Exception e) { e.printStackTrace(); }
// after
try { matcher = factory.getMatcher(config); }
catch (IllegalArgumentException e) {
  logger.log(WARNING, "Bad CelMatcher config", e.getCause()); // inspect cause
  nackConfig(config, e.getMessage());
}
Defensive patterns

Strategy: try-catch

Validate before calling

if (!TYPE_URL.equals(config.getTypedConfig().getTypeUrl()))
  throw new IllegalArgumentException("unexpected typeUrl: " + config.getTypedConfig().getTypeUrl());

Type guard

boolean isCelMatcherConfig(TypedExtensionConfig c) { return TYPE_URL.equals(c.getTypedConfig().getTypeUrl()); }

Try / catch

try { return factory.getMatcher(config); }
catch (IllegalArgumentException e) {
  logger.log(WARNING, "Invalid CelMatcher config", e.getCause());
  nackConfig(config, e.getMessage());
  return null;
}

Prevention

When it happens

Trigger: Any exception during getMatcher(): typed_config cannot be unpacked to the CelMatcher proto type, expr_match or cel_expr_checked missing, or CelMatcher.compile() rejecting a non-BOOL AST.

Common situations: Wrong type_url / mismatched packed Any payload; older or newer proto schemas on control plane vs data plane; non-boolean CEL expressions; version skew where the client lacks a referenced xDS matcher type.

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — 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/1886537e9051edd7. Report an issue: GitHub.