slackhq/nebula · error
winrio.Socket error: %w
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.
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)
Solutions
- Switch to the standard UDP implementation instead of RIO in the config
- Enable/repair IPv6 support on the host since the socket is AF_INET6
- Run on a Windows version with full Winsock RIO support (Windows 8/Server 2012+)
- 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
- Only enable the RIO UDP path on Windows 8/Server 2012 or newer
- Ensure IPv6 is enabled on the host (socket is AF_INET6)
- Verify WSAStartup/Winsock is healthy in the hosting environment
- Ship a config switch to disable RIO without code changes
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.