{"id":"ad9846c195115f46","repo":"go-redis/redis","slug":"redis-failed-to-parse-float-q-v","errorCode":null,"errorMessage":"redis: failed to parse float %q: %v","messagePattern":"redis: failed to parse float %q: (.+?)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/util/convert.go","lineNumber":27,"sourceCode":"// ParseFloat parses a Redis RESP3 float reply into a Go float64,\n// handling \"inf\", \"-inf\", \"nan\" per Redis conventions.\nfunc ParseStringToFloat(s string) (float64, error) {\n\tswitch s {\n\tcase \"inf\":\n\t\treturn math.Inf(1), nil\n\tcase \"-inf\":\n\t\treturn math.Inf(-1), nil\n\tcase \"nan\", \"-nan\":\n\t\treturn math.NaN(), nil\n\t}\n\treturn strconv.ParseFloat(s, 64)\n}\n\n// MustParseFloat is like ParseFloat but panics on parse errors.\nfunc MustParseFloat(s string) float64 {\n\tf, err := ParseStringToFloat(s)\n\tif err != nil {\n\t\tpanic(fmt.Sprintf(\"redis: failed to parse float %q: %v\", s, err))\n\t}\n\treturn f\n}\n\n// SafeIntToInt32 safely converts an int to int32, returning an error if overflow would occur.\nfunc SafeIntToInt32(value int, fieldName string) (int32, error) {\n\tif value > math.MaxInt32 {\n\t\treturn 0, fmt.Errorf(\"redis: %s value %d exceeds maximum allowed value %d\", fieldName, value, math.MaxInt32)\n\t}\n\tif value < math.MinInt32 {\n\t\treturn 0, fmt.Errorf(\"redis: %s value %d is below minimum allowed value %d\", fieldName, value, math.MinInt32)\n\t}\n\treturn int32(value), nil\n}\n","sourceCodeStart":9,"sourceCodeEnd":42,"githubUrl":"https://github.com/go-redis/redis/blob/36d97525cd8076aed67cddf54778e9ea84550929/internal/util/convert.go#L9-L42","documentation":"MustParseFloat panics when ParseStringToFloat fails to convert a string to float64. ParseStringToFloat handles inf/-inf/nan specially then falls back to strconv.ParseFloat, which fails on malformed numeric strings. MustParseFloat is used internally for RESP3 float replies and re-exported via the helper package; the panic indicates an unexpected (corrupt) float from Redis or a bad caller-provided string.","triggerScenarios":"Internally when parsing a RESP3 float reply that is not a valid number (server/protocol corruption). Externally when a caller passes a non-numeric string to helper.MustParseFloat / util.MustParseFloat.","commonSituations":"A custom RESP proxy emitting malformed floats, RESP2/RESP3 protocol corruption on the wire, or a caller misusing the public MustParseFloat helper on untrusted input.","solutions":["If calling the public helper, use util.ParseStringToFloat (which returns an error) instead of MustParseFloat and handle the error.","Validate the string is numeric before calling MustParseFloat when working with untrusted input.","If this surfaces from internal RESP3 parsing, inspect the server/proxy output and connection integrity (TLS, network errors)."],"exampleFix":"// before (helper)\nf := util.MustParseFloat(userInput) // panics on \"abc\"\n\n// after\nf, err := util.ParseStringToFloat(userInput)\nif err != nil { return err }","handlingStrategy":"validation","validationCode":"f, err := util.ParseStringToFloat(s)\nif err != nil {\n    return 0, fmt.Errorf(\"invalid float %q: %w\", s, err)\n}","typeGuard":null,"tryCatchPattern":"// If you must keep MustParseFloat on untrusted input, isolate the panic:\nfunc safeFloat(s string) (f float64, err error) {\n    defer func() {\n        if r := recover(); r != nil {\n            err = fmt.Errorf(\"parse float %q: %v\", s, r)\n        }\n    }()\n    return util.MustParseFloat(s), nil\n}","preventionTips":["Prefer util.ParseStringToFloat (returns error) over MustParseFloat for any non-internal input.","Never feed untrusted strings to Must* helpers.","If this surfaces from RESP3 parsing, suspect wire/proxy corruption rather than caller code."],"tags":["convert","float","panic","resp3","parsing","internal"],"analyzedSha":"36d97525cd8076aed67cddf54778e9ea84550929","analyzedAt":"2026-08-06T01:08:27.376Z","schemaVersion":2}