grpc/grpc-go · error

"headers" %d: "values" is not present

Error message

"headers" %d: "values" is not present

What it means

Returned by parseHeaders (rbac_translator.go:240) when a header matcher has a key but no "values" array (or an empty one). A header permission rule needs at least one value to match against, so a values-less entry is rejected. The %d is the offending entry index.

Source

Thrown at authz/rbac_translator.go:240

	"upgrade":             true,
}

func unsupportedHeader(key string) bool {
	return key[0] == ':' || strings.HasPrefix(key, "grpc-") || unsupportedHeaders[key]
}

func parseHeaders(headers []header) ([]*v3rbacpb.Permission, error) {
	hs := make([]*v3rbacpb.Permission, 0, len(headers))
	for i, header := range headers {
		if header.Key == "" {
			return nil, fmt.Errorf(`"headers" %d: "key" is not present`, i)
		}
		header.Key = strings.ToLower(header.Key)
		if unsupportedHeader(header.Key) {
			return nil, fmt.Errorf(`"headers" %d: unsupported "key" %s`, i, header.Key)
		}
		if len(header.Values) == 0 {
			return nil, fmt.Errorf(`"headers" %d: "values" is not present`, i)
		}
		values := parseHeaderValues(header.Key, header.Values)
		hs = append(hs, permissionOr(values))
	}
	return hs, nil
}

func parseRequest(request request) (*v3rbacpb.Permission, error) {
	var and []*v3rbacpb.Permission
	if len(request.Paths) > 0 {
		and = append(and, permissionOr(parsePaths(request.Paths)))
	}
	if len(request.Headers) > 0 {
		headers, err := parseHeaders(request.Headers)
		if err != nil {
			return nil, err
		}
		and = append(and, permissionAnd(headers))

View on GitHub (pinned to 03255a9237)

Solutions

  1. Add a non-empty "values" array to every header matcher entry.
  2. If you want presence-based matching, list the expected value(s) or reconsider the rule structure.
  3. Validate the policy JSON with a schema requiring values when key is present.
  4. Inspect the entry at the reported index and fill in its values.

Example fix

// before
{"headers":[{"key":"x-role"}]}

// after
{"headers":[{"key":"x-role","values":["admin"]}]}
Defensive patterns

Strategy: validation

Validate before calling

for i, h := range policyHeaders {
    if len(h.Values) == 0 {
        return fmt.Errorf("headers[%d] missing values", i)
    }
}

Try / catch

interceptor, err := authz.NewStatic(policyJSON)
if err != nil {
    return fmt.Errorf("invalid authz policy: %w", err)
}

Prevention

When it happens

Trigger: A policy "headers" entry like {"key":"x-foo"} with no "values" field, or "values":[] with zero elements.

Common situations: Omitting values thinking the key alone matches presence; copy-paste truncation; policy generator dropping empty arrays.

Related errors


AI-assisted analysis of grpc/grpc-go@03255a9237 (2026-08-07). Data as JSON: /api/errors/580102bfa45840b1. Report an issue: GitHub.