{"record":{"id":"0730b2652094012f","repo":"gastownhall/beads","slug":"allocating-ephemeral-port-w","errorCode":null,"errorMessage":"allocating ephemeral port: %w","messagePattern":"allocating ephemeral port: %w","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/doltserver/doltserver.go","lineNumber":388,"sourceCode":"func pidPath(beadsDir string) string  { return filepath.Join(beadsDir, PIDFileName) }\nfunc logPath(beadsDir string) string  { return filepath.Join(beadsDir, \"dolt-server.log\") }\nfunc lockPath(beadsDir string) string { return filepath.Join(beadsDir, \"dolt-server.lock\") }\nfunc portPath(beadsDir string) string { return filepath.Join(beadsDir, PortFileName) }\n\n// MaxDoltServers is the hard ceiling on concurrent dolt sql-server processes.\n// Allows up to 3 (e.g., multiple projects).\nfunc maxDoltServers() int {\n\treturn 3\n}\n\n// allocateEphemeralPort asks the OS for a free TCP port on host.\n// It binds to port 0, reads the assigned port, and closes the listener.\n// The caller should pass the returned port to dolt sql-server promptly\n// to minimize the TOCTOU window.\nfunc allocateEphemeralPort(host string) (int, error) {\n\tln, err := net.Listen(\"tcp\", net.JoinHostPort(host, \"0\"))\n\tif err != nil {\n\t\treturn 0, fmt.Errorf(\"allocating ephemeral port: %w\", err)\n\t}\n\tport := ln.Addr().(*net.TCPAddr).Port\n\t_ = ln.Close()\n\treturn port, nil\n}\n\n// isPortAvailable checks if a TCP port is available for binding.\nfunc isPortAvailable(host string, port int) bool {\n\taddr := net.JoinHostPort(host, strconv.Itoa(port))\n\tln, err := net.Listen(\"tcp\", addr)\n\tif err != nil {\n\t\treturn false\n\t}\n\t_ = ln.Close()\n\treturn true\n}\n\n// reclaimPort ensures an explicit (user-configured) port is available for use.","sourceCodeStart":370,"sourceCodeEnd":406,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/doltserver/doltserver.go#L370-L406","documentation":"allocateEphemeralPort asks the kernel for a free TCP port by binding to host:0 via net.Listen, reading the assigned port, and closing the listener. This error wraps any net.Listen failure while obtaining that ephemeral port, so Start() cannot proceed to launch dolt sql-server.","triggerScenarios":"Start() calling allocateEphemeralPort(host) where net.Listen(\"tcp\", host:0) fails — host resolves to an address with no local interface, IPv6 host on a machine without IPv6 support, or restrictive firewall/SELinux policy blocking socket bind.","commonSituations":"BEADS_DOLT_SERVER_HOST configured to a hostname that doesn't resolve locally or to a remote host, hosts with IPv6 disabled receiving an IPv6 bind address, sandboxed CI runners denying socket creation.","solutions":["Read the wrapped net error (e.g. 'lookup host: no such host', 'cannot assign requested address')","Verify the configured host is a local interface or empty string for all interfaces","Use 127.0.0.1 or 'localhost' instead of an unresolvable/remote hostname","If using IPv6, confirm the host supports it (ip -6 addr) or switch to IPv4","Check firewall/SELinux rules that may block TCP binds"],"exampleFix":"// before: host set to a remote machine\nexport BEADS_DOLT_SERVER_HOST=db.internal.example.com\n// after: bind locally; point clients at the remote host explicitly\nexport BEADS_DOLT_SERVER_HOST=127.0.0.1","handlingStrategy":"retry","validationCode":"// Pre-check that the host is bindable locally\nhost := os.Getenv(\"BEADS_DOLT_SERVER_HOST\")\nif host != \"\" && net.ParseIP(host) != nil {\n    addrs, _ := net.InterfaceAddrs()\n    found := false\n    for _, a := range addrs {\n        if strings.HasPrefix(a.String(), host+\"/\") { found = true }\n    }\n    if !found && host != \"127.0.0.1\" && host != \"::1\" {\n        // host is not a local interface — bind will likely fail\n    }\n}","typeGuard":null,"tryCatchPattern":"port, err := doltserver.Start(beadsDir)\nif err != nil && strings.Contains(err.Error(), \"allocating ephemeral port\") {\n    // retry once, or fall back to default host\n    os.Unsetenv(\"BEADS_DOLT_SERVER_HOST\")\n    port, err = doltserver.Start(beadsDir)\n}","preventionTips":["Leave BEADS_DOLT_SERVER_HOST unset or use 127.0.0.1 unless you know the interface exists","Verify IPv6 support before configuring an IPv6 bind host","In sandboxes/CI, confirm socket creation is permitted","Keep the TOCTOU window small: start the server promptly after allocation"],"tags":["network","tcp","port-allocation","bind"],"backgroundTag":"port-bind-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}