{"record":{"id":"e38d9868ae4c9b7a","repo":"cli/cli","slug":"failed-to-listen-to-local-port-over-tcp-w","errorCode":null,"errorMessage":"failed to listen to local port over tcp: %w","messagePattern":"failed to listen to local port over tcp: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/codespaces/codespaces.go","lineNumber":144,"sourceCode":"\t}\n\n\treturn codespace, nil\n}\n\n// ListenTCP starts a localhost tcp listener on 127.0.0.1 (unless allInterfaces is true) and returns the listener and bound port\nfunc ListenTCP(port int, allInterfaces bool) (*net.TCPListener, int, error) {\n\thost := \"127.0.0.1\"\n\tif allInterfaces {\n\t\thost = \"\"\n\t}\n\n\taddr, err := net.ResolveTCPAddr(\"tcp\", fmt.Sprintf(\"%s:%d\", host, port))\n\tif err != nil {\n\t\treturn nil, 0, fmt.Errorf(\"failed to build tcp address: %w\", err)\n\t}\n\tlistener, err := net.ListenTCP(\"tcp\", addr)\n\tif err != nil {\n\t\treturn nil, 0, fmt.Errorf(\"failed to listen to local port over tcp: %w\", err)\n\t}\n\tport = listener.Addr().(*net.TCPAddr).Port\n\n\treturn listener, port, nil\n}\n","sourceCodeStart":126,"sourceCodeEnd":150,"githubUrl":"https://github.com/cli/cli/blob/0eeec0b92edbe70199f9768522f831d3534f41ad/internal/codespaces/codespaces.go#L126-L150","documentation":"Thrown by ListenTCP when net.ListenTCP cannot bind the TCP listener at 127.0.0.1:port (or 0.0.0.0 when allInterfaces is true). This is the classic bind failure: the port is already in use, the port is privileged (<1024) for a non-root user, or the address is otherwise unavailable.","triggerScenarios":"Local port forwarding for a codespace (gh codespace ports forward / ssh) where the local port is occupied by another process, a previous forwarding session did not release the port, or a privileged port was requested without privileges; with allInterfaces=true, binding 0.0.0.0 may be blocked by firewall policy.","commonSituations":"Running two forwardings of the same local port; a stale gh process holding the port; choosing ports <1024; port already taken by a dev server (3000, 8080, ...).","solutions":["Free the port: find the process with lsof -i :PORT (macOS/Linux) or netstat -ano | findstr PORT (Windows) and stop it.","Use a different local port, or pass port 0 to let the OS pick a free one (the actual bound port is returned).","For privileged ports, choose >=1024 unless running with appropriate capabilities.","Kill stale gh processes from earlier sessions (ps aux | grep gh)."],"exampleFix":"// before\nlistener, port, err := codespaces.ListenTCP(3000, false)\n\n// after\nlistener, port, err := codespaces.ListenTCP(0, false) // OS picks a free port\nfmt.Println(\"forwarding on local port:\", port)","handlingStrategy":"validation","validationCode":"func portAvailable(port int) bool {\n    ln, err := net.Listen(\"tcp\", fmt.Sprintf(\"127.0.0.1:%d\", port))\n    if err != nil {\n        return false\n    }\n    ln.Close()\n    return true\n}\n\nif port != 0 && !portAvailable(port) {\n    return fmt.Errorf(\"local port %d already in use\", port)\n}","typeGuard":null,"tryCatchPattern":"listener, port, err := codespaces.ListenTCP(wantPort, allInterfaces)\nif err != nil {\n    if strings.Contains(err.Error(), \"failed to listen\") {\n        listener, port, err = codespaces.ListenTCP(0, allInterfaces) // fall back to OS-assigned port\n    }\n    if err != nil {\n        return err\n    }\n}","preventionTips":["Probe port availability before binding.","Fall back to port 0 when the desired port is taken.","Clean up listeners with defer listener.Close() to avoid leaking ports."],"tags":["go","tcp","port-in-use","bind","codespaces","port-forwarding"],"backgroundTag":null,"analyzedSha":"0eeec0b92edbe70199f9768522f831d3534f41ad","analyzedAt":"2026-08-15T12:31:05.478Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}