{"record":{"id":"e25fcc4e475ff2f0","repo":"schollz/croc","slug":"not-enough-open-ports-to-run-local-relay","errorCode":null,"errorMessage":"not enough open ports to run local relay","messagePattern":"not enough open ports to run local relay","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"src/croc/croc.go","lineNumber":1083,"sourceCode":"\tfmt.Fprintf(os.Stderr, \"\\r                                 \")\n\toutput, colorEnabled := termui.Output(os.Stderr)\n\tif displayName != \"\" {\n\t\tfname = quotedFilename(displayName, colorEnabled)\n\t}\n\tif c.TotalNumberFolders > 0 {\n\t\tfmt.Fprintf(output, \"\\rSending %s and %s (%s)\\n\", fname, folderName, utils.ByteCountDecimal(totalFilesSize))\n\t} else {\n\t\tfmt.Fprintf(output, \"\\rSending %s (%s)\\n\", fname, utils.ByteCountDecimal(totalFilesSize))\n\t}\n\treturn\n}\n\nfunc (c *Client) setupLocalRelay() {\n\t// setup the relay locally\n\tfirstPort, _ := strconv.Atoi(c.Options.RelayPorts[0])\n\topenPorts := utils.FindOpenPorts(\"127.0.0.1\", firstPort, len(c.Options.RelayPorts))\n\tif len(openPorts) < len(c.Options.RelayPorts) {\n\t\tpanic(\"not enough open ports to run local relay\")\n\t}\n\tfor i, port := range openPorts {\n\t\tc.Options.RelayPorts[i] = fmt.Sprint(port)\n\t}\n\t// Capture the local relay control port before any goroutine that handles\n\t// the external relay can overwrite c.Options.RelayPorts.\n\tc.localRelayPort = c.Options.RelayPorts[0]\n\tlocalRelayPorts := append([]string(nil), c.Options.RelayPorts...)\n\tlocalRelayBanner := strings.Join(localRelayPorts[1:], \",\")\n\tfor _, port := range localRelayPorts {\n\t\tgo func(portStr string) {\n\t\t\tdebugString := \"warn\"\n\t\t\tif c.Options.Debug {\n\t\t\t\tdebugString = \"debug\"\n\t\t\t}\n\t\t\terr := c.stop.run(\n\t\t\t\tdebugString,\n\t\t\t\t\"\",","sourceCodeStart":1065,"sourceCodeEnd":1101,"githubUrl":"https://github.com/schollz/croc/blob/e25f1bdc04f07f094d50b0a1bf67e2563944b57a/src/croc/croc.go#L1065-L1101","documentation":"Go panic in setupLocalRelay(): utils.FindOpenPorts on 127.0.0.1 starting at RelayPorts[0] returned fewer open ports than len(Options.RelayPorts). The local relay must bind every configured port simultaneously; if any are occupied, croc panics instead of silently degrading.","triggerScenarios":"Running with a local relay while another process already listens on one of the configured ports: a previous croc instance still running, a concurrent second transfer, or another service (dev server, docker container publishing the range). Default ports occupy several consecutive ports starting at 9009.","commonSituations":"Two croc transfers at once on one machine; leftover croc process from a crashed session; docker publishing 9009-9013; ephemeral-port pressure breaking the consecutive run.","solutions":["Find and stop the squatter: lsof -i :9009-9013 or ss -ltnp, then kill the process (pkill -f croc for stale instances)","Pass a different range: --relay-ports 10001-10006","Library embedders: probe with utils.FindOpenPorts yourself and supply a confirmed-open list instead of panicking"],"exampleFix":"# before\ncroc --relay --relay-ports 9009-9013 send file.bin  # 9010 occupied -> panic\n\n# after\nlsof -i :9009-9013  # find and stop the conflicting listener\ncroc --relay --relay-ports 10001-10006 send file.bin","handlingStrategy":"validation","validationCode":"// Go: probe ports before starting the local relay\nfirst, _ := strconv.Atoi(opts.RelayPorts[0])\nif len(utils.FindOpenPorts(\"127.0.0.1\", first, len(opts.RelayPorts))) < len(opts.RelayPorts) {\n    return fmt.Errorf(\"relay ports %v unavailable; pass --relay-ports with a free range\", opts.RelayPorts)\n}","typeGuard":null,"tryCatchPattern":"// Panic path: pre-check ports as above, or run croc in a subprocess and map its non-zero exit/panic output to a 'ports busy' message for the user","preventionTips":["Check the relay range with ss -ltnp / lsof before starting transfers","Give concurrent croc transfers distinct --relay-ports ranges","Kill stale croc processes before relaunching"],"tags":["go","panic","relay","ports","local-server"],"backgroundTag":null,"analyzedSha":"e25f1bdc04f07f094d50b0a1bf67e2563944b57a","analyzedAt":"2026-08-15T12:53:39.096Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}