cli/cli · error

failed to listen to local port over tcp: %w

Error message

failed to listen to local port over tcp: %w

What it means

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.

Source

Thrown at internal/codespaces/codespaces.go:144

	}

	return codespace, nil
}

// ListenTCP starts a localhost tcp listener on 127.0.0.1 (unless allInterfaces is true) and returns the listener and bound port
func ListenTCP(port int, allInterfaces bool) (*net.TCPListener, int, error) {
	host := "127.0.0.1"
	if allInterfaces {
		host = ""
	}

	addr, err := net.ResolveTCPAddr("tcp", fmt.Sprintf("%s:%d", host, port))
	if err != nil {
		return nil, 0, fmt.Errorf("failed to build tcp address: %w", err)
	}
	listener, err := net.ListenTCP("tcp", addr)
	if err != nil {
		return nil, 0, fmt.Errorf("failed to listen to local port over tcp: %w", err)
	}
	port = listener.Addr().(*net.TCPAddr).Port

	return listener, port, nil
}

View on GitHub (pinned to 0eeec0b92e)

Solutions

  1. Free the port: find the process with lsof -i :PORT (macOS/Linux) or netstat -ano | findstr PORT (Windows) and stop it.
  2. Use a different local port, or pass port 0 to let the OS pick a free one (the actual bound port is returned).
  3. For privileged ports, choose >=1024 unless running with appropriate capabilities.
  4. Kill stale gh processes from earlier sessions (ps aux | grep gh).

Example fix

// before
listener, port, err := codespaces.ListenTCP(3000, false)

// after
listener, port, err := codespaces.ListenTCP(0, false) // OS picks a free port
fmt.Println("forwarding on local port:", port)
Defensive patterns

Strategy: validation

Validate before calling

func portAvailable(port int) bool {
    ln, err := net.Listen("tcp", fmt.Sprintf("127.0.0.1:%d", port))
    if err != nil {
        return false
    }
    ln.Close()
    return true
}

if port != 0 && !portAvailable(port) {
    return fmt.Errorf("local port %d already in use", port)
}

Try / catch

listener, port, err := codespaces.ListenTCP(wantPort, allInterfaces)
if err != nil {
    if strings.Contains(err.Error(), "failed to listen") {
        listener, port, err = codespaces.ListenTCP(0, allInterfaces) // fall back to OS-assigned port
    }
    if err != nil {
        return err
    }
}

Prevention

When it happens

Trigger: 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.

Common situations: 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, ...).

Related errors


AI-assisted analysis of cli/cli@0eeec0b92e (2026-08-15). Data as JSON: /api/errors/e38d9868ae4c9b7a. Report an issue: GitHub.