{"record":{"id":"61d89c82116e4cc2","repo":"grpc/grpc-go","slug":"min-v-is-greater-than-max-v","errorCode":null,"errorMessage":"min %v is greater than max %v","messagePattern":"min (.+?) is greater than max (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"balancer/ringhash/config.go","lineNumber":55,"sourceCode":"func parseConfig(c json.RawMessage) (*iringhash.LBConfig, error) {\n\tvar cfg iringhash.LBConfig\n\tif err := json.Unmarshal(c, &cfg); err != nil {\n\t\treturn nil, err\n\t}\n\tif cfg.MinRingSize > ringHashSizeUpperBound {\n\t\treturn nil, fmt.Errorf(\"min_ring_size value of %d is greater than max supported value %d for this field\", cfg.MinRingSize, ringHashSizeUpperBound)\n\t}\n\tif cfg.MaxRingSize > ringHashSizeUpperBound {\n\t\treturn nil, fmt.Errorf(\"max_ring_size value of %d is greater than max supported value %d for this field\", cfg.MaxRingSize, ringHashSizeUpperBound)\n\t}\n\tif cfg.MinRingSize == 0 {\n\t\tcfg.MinRingSize = defaultMinSize\n\t}\n\tif cfg.MaxRingSize == 0 {\n\t\tcfg.MaxRingSize = defaultMaxSize\n\t}\n\tif cfg.MinRingSize > cfg.MaxRingSize {\n\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)","sourceCodeStart":37,"sourceCodeEnd":73,"githubUrl":"https://github.com/grpc/grpc-go/blob/03255a9237b6eb32710f6bc4f2de9a675b99fe36/balancer/ringhash/config.go#L37-L73","documentation":"Returned by ringhash.parseConfig (config.go:54-56) when, after applying defaults (min->1024, max->4096 when zero) and the upper-bound clamp, MinRingSize ends up greater than MaxRingSize. The ring requires min <= max so that the actual ring size is chosen uniformly in [min,max]. The %v values are the final min and max.","triggerScenarios":"Config explicitly sets minRingSize larger than maxRingSize (e.g. min=8192, max=4096). Note: leaving both zero is fine because defaults satisfy min<=max; this only fires when an explicit inversion exists.","commonSituations":"Swapping the two fields when hand-writing config. xDS control plane emitting inverted min/max. Defaults masking part of the problem (only the explicit inversion triggers it).","solutions":["Ensure minRingSize <= maxRingSize in the config.","Prefer relying on defaults (omit both) unless you have a measured reason to tune them.","If from xDS, fix minimumRingSize/maximumRingSize ordering in the Cluster resource."],"exampleFix":"// before\nraw := `{\"minRingSize\": 8192, \"maxRingSize\": 4096}` // min > max -> error\n\n// after\nraw := `{\"minRingSize\": 2048, \"maxRingSize\": 8192}`","handlingStrategy":"validation","validationCode":"func validateRingSizeOrder(raw []byte) error {\n    var c struct{ MinRingSize, MaxRingSize uint64 `json:\"minRingSize\"` } // illustrative\n    var full struct {\n        MinRingSize uint64 `json:\"minRingSize\"`\n        MaxRingSize uint64 `json:\"maxRingSize\"`\n    }\n    _ = json.Unmarshal(raw, &full)\n    if full.MinRingSize != 0 && full.MaxRingSize != 0 && full.MinRingSize > full.MaxRingSize {\n        return fmt.Errorf(\"min %d > max %d\", full.MinRingSize, full.MaxRingSize)\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["When setting both, always set min <= max.","Prefer omitting both and using defaults unless tuning is measured.","Add a config-builder test asserting min<=max."],"tags":["go","grpc","load-balancing","ring-hash","config"],"analyzedSha":"03255a9237b6eb32710f6bc4f2de9a675b99fe36","analyzedAt":"2026-08-07T00:29:34.215Z","schemaVersion":2},"datasetVersion":"2026-08-07T03:17:09.362Z"}