grpc/grpc-java · error · IllegalArgumentException

CEL expression references unknown variable:

Error message

CEL expression references unknown variable: 

What it means

CelCommon.checkAllowedReferences whitelists what a CEL expression may reference in xDS matchers. Only the request variable (REQUEST_VARIABLE) is allowed as a variable reference; any other free variable in the AST triggers this IllegalArgumentException. This sandboxing prevents CEL expressions from accessing unsupported data.

Source

Thrown at xds/src/main/java/io/grpc/xds/internal/matcher/CelCommon.java:97

      .setStandardEnvironmentEnabled(false)
      .setStandardFunctions(FUNCTIONS)
      .setOptions(CEL_OPTIONS)
      .build();

  private CelCommon() {}

  /**
   * Validates that the AST only references the allowed variable ("request")
   * and supported functions as defined in gRFC A106.
   */
  static void checkAllowedReferences(CelAbstractSyntaxTree ast) {
    for (Map.Entry<Long, CelReference> entry : ast.getReferenceMap().entrySet()) {
      CelReference ref = entry.getValue();

      // Check for variables (where overloadIds is empty)
      if (!ref.value().isPresent() && ref.overloadIds().isEmpty()) {
        if (!REQUEST_VARIABLE.equals(ref.name())) {
          throw new IllegalArgumentException(
              "CEL expression references unknown variable: " + ref.name());
        }
      } else if (!ref.overloadIds().isEmpty()) {
        String name = ref.name();
        if (name.isEmpty()) {
          boolean allowed = false;
          for (String id : ref.overloadIds()) {
            if (id.equals("add_string") || id.equals("add_list") || id.endsWith("_to_string")) {
              allowed = false;
              break;
            }
            if (ALLOWED_EXACT_OVERLOAD_IDS.contains(id)
                || ALLOWED_OVERLOAD_ID_PREFIX_PATTERN.matcher(id).matches()) {
              allowed = true;
              break;
            }
          }
          if (!allowed) {

View on GitHub (pinned to 64daddc1f3)

Solutions

  1. Reference only the request variable in the expression (e.g., request.headers['x-y'])
  2. Fix typos in variable names in the CEL expression
  3. Remove references to variables not declared in this library's CEL environment
  4. Check the AST reference map (or compile with the same CelEnvironment) to see which variable was rejected

Example fix

// before
CEL: src.headers['x-a'] == 'b'
// after
CEL: request.headers['x-a'] == 'b'
Defensive patterns

Strategy: try-catch

Validate before calling

// verify only 'request' appears as a variable
if (!Set.of("request").containsAll(extractVariableNames(celSource))) {
  throw new IllegalArgumentException("CEL may only reference 'request'");
}

Try / catch

try {
  CelCommon.checkAllowedReferences(ast);
} catch (IllegalArgumentException e) {
  log.error("CEL validation failed: {}", e.getMessage());
}

Prevention

When it happens

Trigger: Compiling/validating a CEL expression that references a variable other than request (e.g., a typo'd variable, or variables from a different CEL environment), causing the AST reference map to contain an unknown variable name.

Common situations: Typing requeste/request.headers instead of request; copying CEL from other systems (e.g., Envoy attribute names); enabling variables not present in this library's restricted CEL declaration.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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