gohugoio/hugo · error

unable to obtain a valid tcp port

Error message

unable to obtain a valid tcp port: %v

What it means

helpers.TCPListen (helpers/general.go:38) calls net.Listen("tcp", ":0") then type-asserts the listener's Addr() to *net.TCPAddr. Because the listener is explicitly TCP, the assertion should always hold on a standard runtime; this error only fires if a custom/modified net stack returns a non-TCP address for a tcp listener. It is effectively unreachable in normal usage.

Solutions

  1. Retry the operation once; a transient custom-stack hiccup is the only realistic cause.
  2. Remove any custom net.Listen substitution or runtime shim and use the standard net package.
  3. Report it as an environment/runtime issue if it reproduces on stock Hugo.
Defensive patterns

Strategy: retry

Validate before calling

// There is no meaningful pre-check; the listener is tcp so the assertion
// should always hold. Keep a retry around TCPListen for robustness.
func TCPListenWithRetry() (net.Listener, *net.TCPAddr, error) {
    return helpers.TCPListen()
}

Try / catch

l, addr, err := helpers.TCPListen()
if err != nil {
    // retry once; if it persists, treat as an environment/runtime fault
    l, addr, err = helpers.TCPListen()
    if err != nil { return err }
}
defer l.Close()

Prevention

When it happens

Trigger: A custom net.Listen substitution (e.g. a test fake or a runtime shim) returning a wrapper Addr that is not *net.TCPAddr; an exotic/sandboxed runtime altering net behaviour. In a stock Hugo build this should never occur.

Common situations: Running under a non-standard runtime or with net-via-linklayer shims; otherwise, this indicates an environment/runtime bug rather than a user config issue.

Related errors


AI-assisted analysis of gohugoio/hugo@52c9bd7908 (2026-08-09). Data as JSON: /api/errors/84290317d8d4e31f. Report an issue: GitHub.

Appendix: source

Thrown at helpers/general.go:48

	"github.com/jdkato/prose/transform"
)

// FilePathSeparator as defined by os.Separator.
const FilePathSeparator = string(filepath.Separator)

// TCPListen starts listening on a valid TCP port.
func TCPListen() (net.Listener, *net.TCPAddr, error) {
	l, err := net.Listen("tcp", ":0")
	if err != nil {
		return nil, nil, err
	}
	addr := l.Addr()
	if a, ok := addr.(*net.TCPAddr); ok {
		return l, a, nil
	}
	l.Close()
	return nil, nil, fmt.Errorf("unable to obtain a valid tcp port: %v", addr)
}

// FirstUpper returns a string with the first character as upper case.
func FirstUpper(s string) string {
	if s == "" {
		return ""
	}
	r, n := utf8.DecodeRuneInString(s)
	return string(unicode.ToUpper(r)) + s[n:]
}

// ReaderToBytes takes an io.Reader argument, reads from it
// and returns bytes.
func ReaderToBytes(lines io.Reader) []byte {
	if lines == nil {
		return []byte{}
	}
	b := bp.GetBuffer()

View on GitHub (pinned to 52c9bd7908)