{"record":{"id":"47e57cbcbbf0756a","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/03255a9237b6eb32710f6bc4f2de9a675b99fe36/balancer/ringhash/config.go#L55-L78","documentation":"Returned by ringhash.parseConfig (config.go:72-74) when requestHashHeader (already validated as a key) ends with the suffix \"-bin\". -bin headers carry binary metadata and cannot be used to derive a string request hash, so they are explicitly rejected by A76 even though they pass ValidateKey. The %q is the header.","triggerScenarios":"requestHashHeader is set to something ending in \"-bin\", e.g. \"user-id-bin\" or \"trace-bin\".","commonSituations":"Reusing an existing binary metadata key name as the hash key. Autocomplete/copy from a -bin header list.","solutions":["Use a non-binary (ASCII string) header as the request hash key: remove the \"-bin\" suffix.","Ensure clients send that key as a normal string header, not appended with -bin."],"exampleFix":"// before\nraw := `{\"requestHashHeader\": \"user-id-bin\"}` // -bin suffix -> error\n\n// after\nraw := `{\"requestHashHeader\": \"user-id\"}`","handlingStrategy":"validation","validationCode":"func rejectBinHeader(h string) error {\n    if strings.HasSuffix(strings.ToLower(h), \"-bin\") {\n        return errors.New(\"hash header must not end with -bin\")\n    }\n    return nil\n}","typeGuard":"func isNonBinHeader(h string) bool { return !strings.HasSuffix(strings.ToLower(h), \"-bin\") }","tryCatchPattern":null,"preventionTips":["Never reuse a binary (-bin) metadata key as the hash source.","Send the hash key as a normal ASCII string header."],"tags":["go","grpc","load-balancing","ring-hash","metadata","config"],"analyzedSha":"03255a9237b6eb32710f6bc4f2de9a675b99fe36","analyzedAt":"2026-08-07T00:29:34.215Z","schemaVersion":2},"datasetVersion":"2026-08-07T03:17:09.362Z"}