{"record":{"id":"19a1b345d3923026","repo":"grpc/grpc-go","slug":"headers-d-unsupported-key-s","errorCode":null,"errorMessage":"\"headers\" %d: unsupported \"key\" %s","messagePattern":"\"headers\" (.+?): unsupported \"key\" (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"authz/rbac_translator.go","lineNumber":237,"sourceCode":"\t\"te\":                  true,\n\t\"trailer\":             true,\n\t\"transfer-encoding\":   true,\n\t\"upgrade\":             true,\n}\n\nfunc unsupportedHeader(key string) bool {\n\treturn key[0] == ':' || strings.HasPrefix(key, \"grpc-\") || unsupportedHeaders[key]\n}\n\nfunc parseHeaders(headers []header) ([]*v3rbacpb.Permission, error) {\n\ths := make([]*v3rbacpb.Permission, 0, len(headers))\n\tfor i, header := range headers {\n\t\tif header.Key == \"\" {\n\t\t\treturn nil, fmt.Errorf(`\"headers\" %d: \"key\" is not present`, i)\n\t\t}\n\t\theader.Key = strings.ToLower(header.Key)\n\t\tif unsupportedHeader(header.Key) {\n\t\t\treturn nil, fmt.Errorf(`\"headers\" %d: unsupported \"key\" %s`, i, header.Key)\n\t\t}\n\t\tif len(header.Values) == 0 {\n\t\t\treturn nil, fmt.Errorf(`\"headers\" %d: \"values\" is not present`, i)\n\t\t}\n\t\tvalues := parseHeaderValues(header.Key, header.Values)\n\t\ths = append(hs, permissionOr(values))\n\t}\n\treturn hs, nil\n}\n\nfunc parseRequest(request request) (*v3rbacpb.Permission, error) {\n\tvar and []*v3rbacpb.Permission\n\tif len(request.Paths) > 0 {\n\t\tand = append(and, permissionOr(parsePaths(request.Paths)))\n\t}\n\tif len(request.Headers) > 0 {\n\t\theaders, err := parseHeaders(request.Headers)\n\t\tif err != nil {","sourceCodeStart":219,"sourceCodeEnd":255,"githubUrl":"https://github.com/grpc/grpc-go/blob/0c51461d27177d997e14c642fe18c11668fc09a3/authz/rbac_translator.go#L219-L255","documentation":"Returned by parseHeaders (rbac_translator.go:237) when a header key is not matchable: keys starting with ':' (pseudo-headers), keys with the 'grpc-' prefix, or keys in the unsupportedHeaders set {host, connection, keep-alive, proxy-authenticate, proxy-authorization, te, trailer, transfer-encoding, upgrade} (defined at line 213). gRPC forbids RBAC matching on these because they are hop-by-hop, transport-managed, or reserved.","triggerScenarios":"A policy rule whose request.headers[].key is one of the reserved/unsupported names (case-insensitive), e.g. \"host\", \":path\", \"grpc-trace-bin\", \"connection\".","commonSituations":"Trying to authorize on the Host header; matching on grpc-* metadata; copying Envoy HTTP route logic into a gRPC policy without adjusting for reserved headers.","solutions":["Remove the unsupported header from the rule, or match on an allowed custom metadata key instead (a non-reserved, non-grpc-prefixed header).","If you need caller identity, use source.principals (mTLS peer) rather than a header.","Re-read the unsupportedHeaders list and pseudo-header rules and audit all header keys in the policy."],"exampleFix":"// before\n\"headers\": [ { \"key\": \"host\", \"values\": [\"api.example.com\"] } ]\n\n// after\n\"headers\": [ { \"key\": \"x-envoy-original-host\", \"values\": [\"api.example.com\"] } ]\n// or remove the header matcher and match on request.paths / source.principals","handlingStrategy":"validation","validationCode":"var unsupportedHeaders = map[string]bool{\n    \"host\": true, \"connection\": true, \"keep-alive\": true,\n    \"proxy-authenticate\": true, \"proxy-authorization\": true,\n    \"te\": true, \"trailer\": true, \"transfer-encoding\": true, \"upgrade\": true,\n}\nfunc allowedHeader(key string) bool {\n    k := strings.ToLower(key)\n    if k == \"\" || k[0] == ':' || strings.HasPrefix(k, \"grpc-\") {\n        return false\n    }\n    return !unsupportedHeaders[k]\n}","typeGuard":null,"tryCatchPattern":"interceptor, err := authz.NewStatic(policyJSON)\nif err != nil {\n    if strings.Contains(err.Error(), `unsupported \"key\"`) {\n        // remove or replace the reserved header in the policy\n    }\n}","preventionTips":["Do not match on host, connection-style, or grpc-* headers in RBAC policies.","Prefer source.principals (mTLS identity) over reserved headers.","Keep the unsupportedHeaders list handy when authoring policies."],"tags":["grpc","authz","rbac","policy","headers","config","go"],"backgroundTag":null,"analyzedSha":"0c51461d27177d997e14c642fe18c11668fc09a3","analyzedAt":"2026-08-11T14:49:15.055Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}