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
- Reference only the request variable in the expression (e.g., request.headers['x-y'])
- Fix typos in variable names in the CEL expression
- Remove references to variables not declared in this library's CEL environment
- 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
- Reference only the request variable in matcher CEL expressions
- Spell 'request' exactly; avoid variable names from other CEL systems
- Compile expressions with the same restricted CelEnvironment used at runtime
- Lint CEL expressions during config CI
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
- CEL expression references unknown function with overload IDs
- CEL expression references unsupported named function:
- Not implemented
- unsupported ExtAuthz service type: only grpc_service is supp
- Invalid ring hash function: " + ringHash.getHashFunction()
AI-assisted analysis of grpc/grpc-java@64daddc1f3 (2026-09-08).
Data as JSON: /api/errors/cb64ac00d631c6ff.
Report an issue: GitHub.