istio/istio · error

outputClaimToHeaders header and claim value must be non-empt

Error message

outputClaimToHeaders header and claim value must be non-empty string

What it means

Thrown by Istio config validation when an authorization policy rule's OutputClaimToHeaders entry has an empty Claim or Header field. OutputClaimToHeaders copies JWT claims into upstream request headers, so both the source claim name and the target header name must be non-empty strings. The check runs per entry after the null check and before ValidateStrictHTTPHeaderName.

Source

Thrown at pkg/config/validation/validation.go:1694

	for _, location := range rule.FromParams {
		if len(location) == 0 {
			errs = multierror.Append(errs, errors.New("location query must be non-empty string"))
		}
	}

	for _, location := range rule.FromCookies {
		if len(location) == 0 {
			errs = multierror.Append(errs, errors.New("cookie name must be non-empty string"))
		}
	}

	for _, claimAndHeaders := range rule.OutputClaimToHeaders {
		if claimAndHeaders == nil {
			errs = multierror.Append(errs, errors.New("outputClaimToHeaders must not be null"))
			continue
		}
		if claimAndHeaders.Claim == "" || claimAndHeaders.Header == "" {
			errs = multierror.Append(errs, errors.New("outputClaimToHeaders header and claim value must be non-empty string"))
			continue
		}
		if err := ValidateStrictHTTPHeaderName(claimAndHeaders.Header); err != nil {
			errs = multierror.Append(errs, err)
		}
	}
	if rule.Timeout != nil {
		if err := agent.ValidateDuration(rule.Timeout); err != nil {
			errs = multierror.Append(errs, err)
		}
	}
	return errs
}

// ValidatePeerAuthentication checks that peer authentication spec is well-formed.
var ValidatePeerAuthentication = RegisterValidateFunc("ValidatePeerAuthentication",
	func(cfg config.Config) (Warning, error) {
		in, ok := cfg.Spec.(*security_beta.PeerAuthentication)

View on GitHub (pinned to 8dc789c5cf)

Solutions

  1. Set both claim and header to non-empty strings in every outputClaimToHeaders entry
  2. Check for trailing indentation errors that made claim/header land outside the map
  3. If generating with Helm/Go, default or assert the values before rendering
  4. Run istioctl validate before applying

Example fix

# before
rules:
  - to: [{ source: { requestPrincipals: ["*"] } }]
    outputClaimToHeaders:
      - header: "x-user"
# after
rules:
  - to: [{ source: { requestPrincipals: ["*"] } }]
    outputClaimToHeaders:
      - claim: "sub"
        header: "x-user"
Defensive patterns

Strategy: validation

Validate before calling

func validateClaimToHeader(entries []ClaimHeader) error {
	for _, e := range entries {
		if strings.TrimSpace(e.Claim) == "" || strings.TrimSpace(e.Header) == "" {
			return fmt.Errorf("outputClaimToHeaders claim and header must be non-empty (got claim=%q header=%q)", e.Claim, e.Header)
		}
	}
	return nil
}

Type guard

func isValidClaimHeader(e *ClaimHeader) bool {
	return e != nil && e.Claim != "" && e.Header != ""
}

Prevention

When it happens

Trigger: An AuthorizationPolicy rule with outputClaimToHeaders: [{ claim: "", header: "x-foo" }] or [{ claim: "sub", header: "" }], applied via kubectl apply, istioctl validate, or AdmissionWebhook.

Common situations: YAML typos or a missing field in the outputClaimToHeaders stanza; templating (Helm) that renders an empty claim name when a value is unset; copying from docs and dropping one key.

Related errors


AI-assisted analysis of istio/istio@8dc789c5cf (2026-08-15). Data as JSON: /api/errors/8504f1f6f3cc2589. Report an issue: GitHub.