{"record":{"id":"8b7cfec3e9bf4694","repo":"juicedata/juicefs","slug":"failed-to-parse-listen-port-v","errorCode":null,"errorMessage":"failed to parse listen port: %v","messagePattern":"failed to parse listen port: (.+?)","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"cmd/debug.go","lineNumber":195,"sourceCode":"\tret, err := exec.Command(lsofArgs[0], lsofArgs[1:]...).CombinedOutput()\n\tif err != nil {\n\t\treturn 0, fmt.Errorf(\"failed to execute command `%s`: %v\", strings.Join(lsofArgs, \" \"), err)\n\t}\n\tlogger.Debugf(\"lsof output: \\n%s\", string(ret))\n\tlines := strings.Split(string(ret), \"\\n\")\n\tif len(lines) == 0 {\n\t\treturn 0, fmt.Errorf(\"pprof will be collected, but no listen port\")\n\t}\n\n\tvar listenPort = -1\n\tfor _, line := range lines {\n\t\tfields := strings.Fields(line)\n\t\tif len(fields) != 0 {\n\t\t\tport, err := func() (port int, err error) {\n\t\t\t\tdefer func() {\n\t\t\t\t\te := recover()\n\t\t\t\t\tif e != nil {\n\t\t\t\t\t\terr = fmt.Errorf(\"failed to parse listen port: %v\", e)\n\t\t\t\t\t}\n\t\t\t\t}()\n\t\t\t\tport, err = strconv.Atoi(strings.Split(fields[len(fields)-2], \":\")[1])\n\t\t\t\tif err != nil {\n\t\t\t\t\tlogger.Errorf(\"failed to parse port %v: %v\", port, err)\n\t\t\t\t}\n\t\t\t\treturn\n\t\t\t}()\n\t\t\tif err != nil {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif port >= 6060 && port <= 6099 && port > listenPort {\n\t\t\t\tif err := checkPort(port, amp); err == nil {\n\t\t\t\t\tlistenPort = port\n\t\t\t\t}\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}","sourceCodeStart":177,"sourceCodeEnd":213,"githubUrl":"https://github.com/juicedata/juicefs/blob/c9a67b23e8e08ec23ec331aa6f1675e2319e921c/cmd/debug.go#L177-L213","documentation":"During `juicefs debug` pprof-port discovery, getPprofPort parses each `lsof -i -nP` LISTEN line for the target PID and extracts the port by splitting the second-to-last field on ':' and taking index 1. The parse runs inside an anonymous func with a deferred recover, so any panic (notably an index-out-of-range from splitting an address that contains no ':') is converted into this wrapped error. The wrapping exists precisely so one malformed lsof line cannot crash the whole debug command.","triggerScenarios":"`juicefs debug <mountpoint>` runs lsof and a LISTEN line has fewer than 2 whitespace fields, or its second-to-last field is an address without ':' (e.g. a Unix socket line, an IPv6/pcrec-format line, or `fields[len(fields)-2]` being the PID itself), causing strings.Split(..., \":\")[1] to panic. The recover converts the panic into 'failed to parse listen port: %v'.","commonSituations":"Environments whose lsof emits non-standard LISTEN lines (busybox lsof, unusual locales, IPv6 addresses, extra columns); the mount was started with a Unix-domain socket instead of a TCP listener; PID reuse picks up unrelated processes with non-TCP listening sockets.","solutions":["Ignore safely: getPprofPort already `continue`s past lines that produce this error; verify other candidate ports in the 6060-6099 range are being tried.","Run `/bin/sh -c \"lsof -i -nP | grep LISTEN | grep <pid>\"` manually and inspect lines whose second-to-last field lacks a ':'; those are the offenders.","Ensure the JuiceFS mount exposes pprof (default net/http/pprof on 6060+) so a valid TCP line exists among lsof output.","Check lsof version/platform differences; prefer parsing the `*:PORT` / `127.0.0.1:PORT` address column explicitly rather than the second-to-last field."],"exampleFix":"// before\nport, err = strconv.Atoi(strings.Split(fields[len(fields)-2], \":\")[1])\n// after\naddr := fields[len(fields)-2]\nif i := strings.LastIndex(addr, \":\"); i >= 0 {\n    port, err = strconv.Atoi(addr[i+1:])\n} else {\n    err = fmt.Errorf(\"no port in address %q\", addr)\n}","handlingStrategy":"validation","validationCode":"addr := fields[len(fields)-2]\nif i := strings.LastIndex(addr, \":\"); i < 0 || i == len(addr)-1 {\n    return fmt.Errorf(\"skipping line: no parsable port in address %q\", addr)\n}\nport, err := strconv.Atoi(addr[i+1:])","typeGuard":"func hasPort(addr string) bool {\n    i := strings.LastIndex(addr, \":\")\n    return i >= 0 && i < len(addr)-1\n}","tryCatchPattern":"// Go: recover converted to error (already used in getPprofPort)\ndefer func() {\n    if e := recover(); e != nil {\n        err = fmt.Errorf(\"failed to parse listen port: %v\", e)\n    }\n}()","preventionTips":["Never index strings.Split results without checking lengths; use strings.LastIndex on the address instead.","Test the lsof-parsing code against IPv6 and Unix-socket LISTEN lines.","Treat each unparsable lsof line as skip-and-continue, not fatal."],"tags":["go","lsof","port-parsing","panic-recovery"],"backgroundTag":"invalid-argument-format","analyzedSha":"c9a67b23e8e08ec23ec331aa6f1675e2319e921c","analyzedAt":"2026-09-06T17:55:48.476Z","contentChangedAt":"2026-09-06T17:55:48.476Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}