kubernetes/kubernetes · error

variable composition is not allowed

Error message

variable composition is not allowed

What it means

Returned as a field.InternalError when validating a ValidatingAdmissionPolicy variable definition and the CEL compiler passed to the validator is not a *plugincel.CompositedCompiler (i.e. it does not support variable composition / expression compilation and storage). This is an internal/server-side configuration problem, not a user-facing CEL expression error.

Source

Thrown at pkg/apis/admissionregistration/validation/validation.go:1028

	} else {
		if compiler, ok := compiler.(*plugincel.CompositedCompiler); ok {
			envType := environment.NewExpressions
			if opts.preexistingExpressions.validationExpressions.Has(v.Expression) {
				envType = environment.StoredExpressions
			}
			variable := &validatingadmissionpolicy.Variable{
				Name:       v.Name,
				Expression: v.Expression,
			}
			result := compiler.CompileAndStoreVariable(variable, plugincel.OptionalVariableDeclarations{
				HasParams:     paramKind != nil,
				HasAuthorizer: true,
			}, envType)
			if result.Error != nil {
				allErrors = append(allErrors, convertCELErrorToValidationError(fldPath.Child("expression"), variable, result.Error))
			}
		} else {
			allErrors = append(allErrors, field.InternalError(fldPath, fmt.Errorf("variable composition is not allowed")))
		}
	}
	return allErrors
}

func validateValidation(compiler plugincel.Compiler, v *admissionregistration.Validation, paramKind *admissionregistration.ParamKind, opts validationOptions, fldPath *field.Path) field.ErrorList {
	var allErrors field.ErrorList
	trimmedExpression := strings.TrimSpace(v.Expression)
	trimmedMsg := strings.TrimSpace(v.Message)
	trimmedMessageExpression := strings.TrimSpace(v.MessageExpression)
	if len(trimmedExpression) == 0 {
		allErrors = append(allErrors, field.Required(fldPath.Child("expression"), "expression is not specified"))
	} else {
		allErrors = append(allErrors, validateValidationExpression(compiler, v.Expression, paramKind != nil, opts, fldPath.Child("expression"))...)
	}
	if len(v.MessageExpression) > 0 && len(trimmedMessageExpression) == 0 {
		allErrors = append(allErrors, field.Invalid(fldPath.Child("messageExpression"), v.MessageExpression, "must be non-empty if specified"))
	} else if len(trimmedMessageExpression) != 0 {

View on GitHub (pinned to 94c1367642)

Solutions

  1. Upgrade the API server to a version that registers the CompositedCompiler for admission policy validation.
  2. If running a custom apiserver, ensure the CEL environment factory returns a *plugincel.CompositedCompiler (see plugincel.NewCompositedCompiler).
  3. If you cannot upgrade, remove spec.variables from the ValidatingAdmissionPolicy and inline the expressions.

Example fix

// before — custom apiserver wires a plain compiler
compiler := cel.NewCompiler(env)

// after — use the composited compiler that supports variable composition
compiler := plugincel.NewCompositedCompiler(env, optionalDeclarations)
Defensive patterns

Strategy: validation

Prevention

When it happens

Trigger: A ValidatingAdmissionPolicy that declares one or more variables (spec.variables) is submitted to an API server whose admission CEL compiler is a plain compiler that lacks the CompositedCompiler type. The validator checks the compiler type at runtime and fails because variable composition requires storing compiled expressions.

Common situations: Running a custom API server build that wires a minimal CEL compiler without the composition plugin; version skew where the API server binary predates variable support but the CRD/policy schema accepts variables; test harness using a mock compiler.

Related errors


AI-assisted analysis of kubernetes/kubernetes@94c1367642 (2026-08-08). Data as JSON: /api/errors/c91aa86541fd0475. Report an issue: GitHub.