{"id":"84290317d8d4e31f","repo":"gohugoio/hugo","slug":"unable-to-obtain-a-valid-tcp-port-v","errorCode":null,"errorMessage":"unable to obtain a valid tcp port: %v","messagePattern":"unable to obtain a valid tcp port: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"helpers/general.go","lineNumber":48,"sourceCode":"\n\t\"github.com/jdkato/prose/transform\"\n)\n\n// FilePathSeparator as defined by os.Separator.\nconst FilePathSeparator = string(filepath.Separator)\n\n// TCPListen starts listening on a valid TCP port.\nfunc TCPListen() (net.Listener, *net.TCPAddr, error) {\n\tl, err := net.Listen(\"tcp\", \":0\")\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\taddr := l.Addr()\n\tif a, ok := addr.(*net.TCPAddr); ok {\n\t\treturn l, a, nil\n\t}\n\tl.Close()\n\treturn nil, nil, fmt.Errorf(\"unable to obtain a valid tcp port: %v\", addr)\n}\n\n// FirstUpper returns a string with the first character as upper case.\nfunc FirstUpper(s string) string {\n\tif s == \"\" {\n\t\treturn \"\"\n\t}\n\tr, n := utf8.DecodeRuneInString(s)\n\treturn string(unicode.ToUpper(r)) + s[n:]\n}\n\n// ReaderToBytes takes an io.Reader argument, reads from it\n// and returns bytes.\nfunc ReaderToBytes(lines io.Reader) []byte {\n\tif lines == nil {\n\t\treturn []byte{}\n\t}\n\tb := bp.GetBuffer()","sourceCodeStart":30,"sourceCodeEnd":66,"githubUrl":"https://github.com/gohugoio/hugo/blob/8a468df065a75c1c7cf9f6850f32148746590ea5/helpers/general.go#L30-L66","documentation":"helpers.TCPListen asks the OS for an ephemeral port by listening on \":0\", then type-asserts the returned net.Addr to *net.TCPAddr to report which port was assigned. This error means the listener was created but its address was not a *net.TCPAddr — an essentially pathological condition indicating something unusual about the network stack or an overridden net implementation, since a TCP listen should always yield a TCPAddr.","triggerScenarios":"Called when `hugo server` needs to auto-pick a free port (e.g. the requested port is taken, or for the LiveReload listener). The failure path requires net.Listen(\"tcp\", \":0\") to succeed but l.Addr() to return a non-TCPAddr, which does not happen with the standard Go runtime on normal systems.","commonSituations":"Exotic or sandboxed environments with nonstandard network namespaces, unusual socket proxying/LD_PRELOAD shims, or heavily restricted seccomp profiles; in practice users far more often see the plain net.Listen error (returned earlier, unwrapped) from firewalls or exhausted ports rather than this specific message.","solutions":["Treat it as an environment problem: rerun outside the sandbox/container network shim, or on the host network (`docker run --network host`) to rule out proxy layers.","Specify an explicit free port with `hugo server --port 1313` (and `--liveReloadPort`) to avoid the ephemeral-port path.","Check for tools intercepting sockets (VPN clients, antivirus, syscall filters) and disable them for the dev server.","If reproducible on a stock OS with a stock Hugo binary, report it upstream with OS and network details — it indicates a Go net anomaly."],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// Probe that an ephemeral port can be bound before starting the server\nl, err := net.Listen(\"tcp\", \"127.0.0.1:0\")\nif err != nil { return fmt.Errorf(\"no free tcp port: %w\", err) }\nl.Close()","typeGuard":null,"tryCatchPattern":"for i := 0; i < 3; i++ {\n    err = startServer()\n    if err == nil || !strings.Contains(err.Error(), \"valid tcp port\") { break }\n    time.Sleep(time.Duration(i+1) * 500 * time.Millisecond)\n}","preventionTips":["Pass an explicit free port with `--port` instead of relying on auto-selection","Kill orphaned dev servers holding ports before relaunching (check with lsof/ss)","In sandboxed environments, ensure the sandbox permits binding loopback TCP ports"],"tags":["hugo","network","tcp","dev-server"],"analyzedSha":"8a468df065a75c1c7cf9f6850f32148746590ea5","analyzedAt":"2026-07-31T21:23:07.045Z","schemaVersion":2}