{"record":{"id":"4ec4729b34ae4961","repo":"grpc/grpc-java","slug":"cel-expression-must-evaluate-to-boolean-got","errorCode":null,"errorMessage":"CEL expression must evaluate to boolean, got: ","messagePattern":"CEL expression must evaluate to boolean, got: ","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"xds/src/main/java/io/grpc/xds/internal/matcher/CelMatcher.java","lineNumber":44,"sourceCode":" * Executes compiled CEL expressions.\n */\nfinal class CelMatcher {\n  private final CelRuntime.Program program;\n\n  private CelMatcher(CelRuntime.Program program) {\n    this.program = program;\n  }\n\n  /**\n   * Compiles the AST into a CelMatcher.\n   * Throws an Exception if evaluation fails during compilation setup.\n   */\n  static CelMatcher compile(CelAbstractSyntaxTree ast)\n      throws CelEvaluationException {\n    // CelEvaluationException -> inside cel-runtime -> Allowed in production signatures\n    // CelValidationException -> inside cel-compiler -> Forbidden in production signatures\n    if (ast.getResultType() != SimpleType.BOOL) {\n      throw new IllegalArgumentException(\n          \"CEL expression must evaluate to boolean, got: \" + ast.getResultType());\n    }\n    CelCommon.checkAllowedReferences(ast);\n    CelRuntime.Program program = CelCommon.RUNTIME.createProgram(ast);\n    return new CelMatcher(program);\n  }\n\n  /**\n   * Evaluates the CEL expression against the input activation.\n   */\n  boolean match(Object input) throws CelEvaluationException {\n    Object result;\n    if (input instanceof CelVariableResolver) {\n      result = program.eval((CelVariableResolver) input);\n    } else {\n      throw new CelEvaluationException(\n          \"Unsupported input type for CEL evaluation: \"\n               + (input == null ? \"null\" : input.getClass().getName()));","sourceCodeStart":26,"sourceCodeEnd":62,"githubUrl":"https://github.com/grpc/grpc-java/blob/64daddc1f3d1975670f769f3e97bde8b2ba32d25/xds/src/main/java/io/grpc/xds/internal/matcher/CelMatcher.java#L26-L62","documentation":"CelMatcher.compile() validates that the parsed CEL AST's result type is BOOL before creating the evaluation program. gRPC xDS CEL matchers are used as boolean predicates for routing/matching decisions, so a non-boolean expression can never produce a match verdict. The compile step fails fast with IllegalArgumentException naming the actual result type.","triggerScenarios":"Calling CelMatcher.compile(ast) with an AST whose getResultType() is not SimpleType.BOOL, e.g. a CEL expression like 'request.headers[\"x\"]' (string) or '1 + 2' (int) instead of a predicate like 'request.headers[\"x\"] == \"y\"'.","commonSituations":"xDS config carrying a CelMatcher whose expr was written as a value expression rather than a boolean comparison; copy-pasting extractor-style expressions (string-typed) into a match context; schema changes where the checked expression type was relaxed or mistyped.","solutions":["Rewrite the CEL expression so it evaluates to bool (add a comparison, e.g. 'req.headers[\\\"x-user\\\"] == \\\"admin\\\"').","Check ast.getResultType() before compiling and reject the config upstream with a clearer message.","If a string value is needed rather than a boolean predicate, use CelStringExtractor.compile() instead of CelMatcher.compile()."],"exampleFix":"// before\nCelMatcher.compile(CelCommon.COMPILER.compile(\"request.headers['x-version']\"));\n// after\nCelMatcher.compile(CelCommon.COMPILER.compile(\"request.headers['x-version'] == 'v2'\"));","handlingStrategy":"validation","validationCode":"if (ast.getResultType() != SimpleType.BOOL) {\n  throw new IllegalArgumentException(\"CEL expr must be bool, got: \" + ast.getResultType());\n}\nCelMatcher matcher = CelMatcher.compile(ast);","typeGuard":"boolean isBoolAst(CelAbstractSyntaxTree ast) { return ast.getResultType() == SimpleType.BOOL; }","tryCatchPattern":"try { return CelMatcher.compile(ast); }\ncatch (IllegalArgumentException e) { logger.warn(\"non-boolean CEL expr\", e); return null; }","preventionTips":["Always end match expressions with an explicit comparison (==, !=, in, matches).","Check ast.getResultType() in config ingestion before compiling.","Use cel-compiler's checked compile so result types are validated early.","Use CelStringExtractor for value expressions and CelMatcher only for predicates."],"tags":["cel","grpc-xds","type-mismatch","matcher"],"backgroundTag":"type-mismatch","analyzedSha":"64daddc1f3d1975670f769f3e97bde8b2ba32d25","analyzedAt":"2026-09-08T06:14:57.704Z","contentChangedAt":"2026-09-08T06:14:57.704Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}