{"record":{"id":"1e613d1bdce79ddf","repo":"grpc/grpc-go","slug":"invalid-requesthashheader-q-key-must-not-end-wit","errorCode":null,"errorMessage":"invalid requestHashHeader %q: key must not end with \"-bin\"","messagePattern":"invalid requestHashHeader %q: key must not end with \"-bin\"","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"balancer/ringhash/config.go","lineNumber":73,"sourceCode":"\t\treturn nil, fmt.Errorf(\"min %v is greater than max %v\", cfg.MinRingSize, cfg.MaxRingSize)\n\t}\n\tif cfg.MinRingSize > envconfig.RingHashCap {\n\t\tcfg.MinRingSize = envconfig.RingHashCap\n\t}\n\tif cfg.MaxRingSize > envconfig.RingHashCap {\n\t\tcfg.MaxRingSize = envconfig.RingHashCap\n\t}\n\tif !envconfig.RingHashSetRequestHashKey {\n\t\tcfg.RequestHashHeader = \"\"\n\t}\n\tif cfg.RequestHashHeader != \"\" {\n\t\tcfg.RequestHashHeader = strings.ToLower(cfg.RequestHashHeader)\n\t\t// See rules in https://github.com/grpc/proposal/blob/master/A76-ring-hash-improvements.md#explicitly-setting-the-request-hash-key\n\t\tif err := metadata.ValidateKey(cfg.RequestHashHeader); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"invalid requestHashHeader %q: %v\", cfg.RequestHashHeader, err)\n\t\t}\n\t\tif strings.HasSuffix(cfg.RequestHashHeader, \"-bin\") {\n\t\t\treturn nil, fmt.Errorf(\"invalid requestHashHeader %q: key must not end with \\\"-bin\\\"\", cfg.RequestHashHeader)\n\t\t}\n\t}\n\treturn &cfg, nil\n}\n","sourceCodeStart":55,"sourceCodeEnd":78,"githubUrl":"https://github.com/grpc/grpc-go/blob/0c51461d27177d997e14c642fe18c11668fc09a3/balancer/ringhash/config.go#L55-L78","documentation":"Returned by ringhash's parseConfig() (balancer/ringhash/config.go:73) when requestHashHeader ends with the suffix '-bin'. Binary headers (-bin suffix) carry raw bytes and cannot be used as a request-hash key because the hash expects a string value. This is enforced after ValidateKey passes.","triggerScenarios":"requestHashHeader is a syntactically valid key but ends in '-bin' (e.g. 'my-key-bin'). The check at line 72 (strings.HasSuffix) fires.","commonSituations":"Operator picks a binary metadata header as the hash source by mistake; an xDS control plane reuses an existing '-bin' header name.","solutions":["Use a non-binary (ASCII string) metadata header as requestHashHeader — it must not end with '-bin'.","If you need to hash on a binary header, convert it to a base64 ASCII header first."],"exampleFix":"// before: binary header used as hash key — rejected\ngrpc.WithDefaultServiceConfig(`{\"loadBalancingConfig\":[{\"ring_hash_experimental\":{\"requestHashHeader\":\"trace-bin\"}}]}`)\n\n// after: use a non-binary ASCII header\ngrpc.WithDefaultServiceConfig(`{\"loadBalancingConfig\":[{\"ring_hash_experimental\":{\"requestHashHeader\":\"trace-id\"}}]}`)","handlingStrategy":"validation","validationCode":"func rejectBinaryHeader(h string) error {\n    if strings.HasSuffix(strings.ToLower(h), \"-bin\") {\n        return errors.New(\"requestHashHeader must not end with -bin\")\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never use a '-bin' (binary) metadata header as the ring hash key.","Use a base64-encoded ASCII header if you need to hash binary data."],"tags":["grpc","balancer","ringhash","config","validation","metadata","header"],"backgroundTag":null,"analyzedSha":"0c51461d27177d997e14c642fe18c11668fc09a3","analyzedAt":"2026-08-11T14:49:15.055Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}