slackhq/nebula · error

winrio.Socket error

Error message

winrio.Socket error: %w

What it means

RIOConn.bind creates the UDP socket via winrio.Socket (Registered I/O socket, not the standard WSASocket) and wraps any failure as 'winrio.Socket error: <cause>'. Without an RIO socket no RIO listener can exist, so bind and listener creation abort.

Solutions

  1. Switch to the standard UDP implementation instead of RIO in the config
  2. Enable/repair IPv6 support on the host since the socket is AF_INET6
  3. Run on a Windows version with full Winsock RIO support (Windows 8/Server 2012+)
  4. Unwrap the error to read the Winsock error code (WSAEAFNOSUPPORT, WSAEPROTONOSUPPORT) and address accordingly

Example fix

// before
listeners:
  ring: rio
// after — use default udp implementation
listeners: {}
Defensive patterns

Strategy: fallback

Validate before calling

// feature-detect RIO before choosing the implementation
rioOK := runtime.GOOS == "windows" && winrioSupported() // e.g. probe winrio.Socket/close
if !rioOK { selectStandardUDPImplementation() }

Try / catch

u, err := udp.NewRIOListener(...)
if err != nil {
    var werr error
    if errors.Unwrap(err) != nil { werr = errors.Unwrap(err) }
    if strings.Contains(err.Error(), "winrio.Socket error") {
        return udp.NewListener(standardCfg) // fall back to non-RIO
    }
    return err
}

Prevention

When it happens

Trigger: Calling udp.NewRIOListener on Windows when winrio.Socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP) fails — typically because RIO is unavailable/unsupported on the platform or WSA initialization failed.

Common situations: Old or stripped-down Windows installs lacking RIO; running in environments (containers, Wine) without full Winsock RIO support; WSAStartup issues in embedded hosts; IPv6 disabled on the host so AF_INET6 socket creation fails.

Related errors


AI-assisted analysis of slackhq/nebula@dd8f660c0a (2026-09-03). Data as JSON: /api/errors/0e7abd961252d9a1. Report an issue: GitHub.

Appendix: source

Thrown at udp/udp_rio_windows.go:90

		return nil, fmt.Errorf("bind: %w", err)
	}

	for i := 0; i < packetsPerRing; i++ {
		err = u.insertReceiveRequest()
		if err != nil {
			return nil, fmt.Errorf("init rx ring: %w", err)
		}
	}

	u.isOpen.Store(true)
	return u, nil
}

func (u *RIOConn) bind(l *slog.Logger, sa windows.Sockaddr) error {
	var err error
	u.sock, err = winrio.Socket(windows.AF_INET6, windows.SOCK_DGRAM, windows.IPPROTO_UDP)
	if err != nil {
		return fmt.Errorf("winrio.Socket error: %w", err)
	}

	// Enable v4 for this socket
	syscall.SetsockoptInt(syscall.Handle(u.sock), syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, 0)

	// Disable reporting of PORT_UNREACHABLE and NET_UNREACHABLE errors from the UDP socket receive call.
	// These errors are returned on Windows during UDP receives based on the receipt of ICMP packets. Disable
	// the UDP receive error returns with these ioctl calls.
	ret := uint32(0)
	flag := uint32(0)
	size := uint32(unsafe.Sizeof(flag))
	err = syscall.WSAIoctl(syscall.Handle(u.sock), syscall.SIO_UDP_CONNRESET, (*byte)(unsafe.Pointer(&flag)), size, nil, 0, &ret, nil, 0)
	if err != nil {
		// This is a best-effort to prevent errors from being returned by the udp recv operation.
		// Quietly log a failure and continue.
		l.Debug("failed to set UDP_CONNRESET ioctl", "error", err)
	}

View on GitHub (pinned to dd8f660c0a)