grpc/grpc-go · error
"headers" %d: "key" is not present
Error message
"headers" %d: "key" is not present
What it means
Returned by parseHeaders in the authz RBAC translator (rbac_translator.go:233) when a header matcher entry in the authorization policy JSON has no "key" field. Every header-based permission rule requires a header name to match against, so a missing key is rejected. The %d is the index of the offending entry.
Source
Thrown at authz/rbac_translator.go:233
"connection": true,
"keep-alive": true,
"proxy-authenticate": true,
"proxy-authorization": true,
"te": true,
"trailer": true,
"transfer-encoding": true,
"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)))View on GitHub (pinned to 03255a9237)
Solutions
- Add a non-empty "key" field to every entry in the policy's "headers" arrays.
- Validate the policy JSON with a schema before deploying it.
- Use the same field name consistently (key, not name/header) per the policy format.
- Find the entry at the reported index and fix or remove it.
Example fix
// before
{"name":[{"headers":[{"values":["xyz"]}]}]}
// after
{"name":[{"headers":[{"key":"x-custom","values":["xyz"]}]}]} Defensive patterns
Strategy: validation
Validate before calling
for i, h := range policyHeaders {
if h.Key == "" {
return fmt.Errorf("headers[%d] missing key", i)
}
} Try / catch
interceptor, err := authz.NewStatic(policyJSON)
if err != nil {
return fmt.Errorf("invalid authz policy: %w", err)
} Prevention
- Validate policy JSON against a schema before deploying.
- Use codegen/templates to produce policy files consistently.
- Check every headers entry has a key and values.
When it happens
Trigger: An authorization policy whose "allow"/"deny" rules contain a "headers" array element without a "key" field, e.g. {"values":["x"]} with no key.
Common situations: Hand-writing policy JSON and omitting the key; a policy generator emitting incomplete header objects; truncation/copy-paste errors in the config.
Related errors
- "headers" %d: unsupported "key" %s
- "headers" %d: "values" is not present
- authz: authorization policy file path is empty
- authz: requires refresh interval(%v) greater than 0s
- policyFile(%s) read failed: %v
AI-assisted analysis of grpc/grpc-go@03255a9237 (2026-08-07).
Data as JSON: /api/errors/bbc9e1c52b9019f5.
Report an issue: GitHub.