grpc/grpc-java · error · CelEvaluationException

Unsupported input type for CEL evaluation:

Error message

Unsupported input type for CEL evaluation: 

What it means

CelMatcher.match() only accepts inputs implementing CelVariableResolver, which supplies the variable bindings during CEL evaluation. Any other object (or null) cannot be resolved into variables, so the call is rejected with CelEvaluationException before the program runs. The message includes the offending class name or 'null'.

Source

Thrown at xds/src/main/java/io/grpc/xds/internal/matcher/CelMatcher.java:60

    // CelValidationException -> inside cel-compiler -> Forbidden in production signatures
    if (ast.getResultType() != SimpleType.BOOL) {
      throw new IllegalArgumentException(
          "CEL expression must evaluate to boolean, got: " + ast.getResultType());
    }
    CelCommon.checkAllowedReferences(ast);
    CelRuntime.Program program = CelCommon.RUNTIME.createProgram(ast);
    return new CelMatcher(program);
  }

  /**
   * Evaluates the CEL expression against the input activation.
   */
  boolean match(Object input) throws CelEvaluationException {
    Object result;
    if (input instanceof CelVariableResolver) {
      result = program.eval((CelVariableResolver) input);
    } else {
      throw new CelEvaluationException(
          "Unsupported input type for CEL evaluation: "
               + (input == null ? "null" : input.getClass().getName()));
    }
    
    if (result instanceof Boolean) {
      return (Boolean) result;
    }
    throw new CelEvaluationException(
        "CEL expression must evaluate to boolean, got: " + result.getClass().getName());
  }
}

View on GitHub (pinned to 64daddc1f3)

Solutions

  1. Wrap the evaluation context in a class implementing CelVariableResolver (e.g. a header-map-backed resolver) and pass that to match().
  2. Null-check the input and build a resolver before calling match().
  3. Catch CelEvaluationException at the call site and fall back to a non-match / default decision.

Example fix

// before
boolean ok = matcher.match(requestHeaders); // Map, unsupported
// after
boolean ok = matcher.match(new HeaderResolver(requestHeaders)); // implements CelVariableResolver
Defensive patterns

Strategy: type-guard

Validate before calling

if (input == null || !(input instanceof CelVariableResolver)) {
  throw new IllegalArgumentException("match() requires a CelVariableResolver");
}

Type guard

boolean isEvaluable(Object input) { return input instanceof CelVariableResolver; }

Try / catch

try { return matcher.match(resolver); }
catch (CelEvaluationException e) { logger.warn("CEL eval failed", e); return false; }

Prevention

When it happens

Trigger: Passing null, a raw Map, a proto request object, or any non-CelVariableResolver value to CelMatcher.match(). Test methods celMatcher_unsupportedInputThrows and celMatcher_nullInputThrows exercise both cases.

Common situations: Calling match() directly with a header map instead of wrapping it in a resolver implementation; refactoring code that previously took typed inputs; unit tests probing null handling.

Understand the failure class

Background: "is not a compatible type" / "cannot merge" errors: when a value's type doesn't match what the library requires — this error's family across 65 libraries.

Related errors


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