slackhq/nebula · error

error tx.Open(): %w

Error message

error tx.Open(): %w

What it means

This error wraps failure of the transmit (tx) ring buffer's Open() during RIO UDP listener setup on Windows, after rx.Open() has succeeded. The tx side allocates its own completion queue and send buffers via winrio. bind() aborts and propagates the underlying OS error via %w.

Source

Thrown at udp/udp_rio_windows.go:127

	ret = 0
	flag = 0
	size = uint32(unsafe.Sizeof(flag))
	SIO_UDP_NETRESET := uint32(syscall.IOC_IN | syscall.IOC_VENDOR | 15)
	err = syscall.WSAIoctl(syscall.Handle(u.sock), SIO_UDP_NETRESET, (*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_NETRESET ioctl", "error", err)
	}

	err = u.rx.Open()
	if err != nil {
		return fmt.Errorf("error rx.Open(): %w", err)
	}

	err = u.tx.Open()
	if err != nil {
		return fmt.Errorf("error tx.Open(): %w", err)
	}

	u.rq, err = winrio.CreateRequestQueue(u.sock, packetsPerRing, 1, packetsPerRing, 1, u.rx.cq, u.tx.cq, 0)
	if err != nil {
		return fmt.Errorf("error CreateRequestQueue: %w", err)
	}

	err = windows.Bind(u.sock, sa)
	if err != nil {
		return fmt.Errorf("error windows.Bind(): %w", err)
	}

	return nil
}

func (u *RIOConn) ListenOut(r EncReader, flush func()) error {
	buffer := make([]byte, MTU)

View on GitHub (pinned to dd8f660c0a)

Solutions

  1. Inspect the wrapped OS error for the precise winrio failure code.
  2. Lower packetsPerRing to shrink the tx completion queue and registered buffer footprint.
  3. Close other RIO sockets or reboot to reclaim non-paged pool if WSAENOBUFS-style errors appear.
  4. Verify Windows version and winsock support for Registered I/O.
Defensive patterns

Strategy: try-catch

Validate before calling

if runtime.GOOS != "windows" { return errors.New("RIO listener only exists on windows") }
// ensure system has headroom before opening large rings
if packetsPerRing > 1024 { return fmt.Errorf("packetsPerRing %d too large", packetsPerRing) }

Type guard

func isTxOpenErr(err error) bool { return err != nil && strings.Contains(err.Error(), "tx.Open()") }

Try / catch

conn, err := udp.NewListener(logger, settings)
if err != nil && strings.Contains(err.Error(), "tx.Open()") {
	// retry once with smaller rings or fail over to a non-RIO path
}

Prevention

When it happens

Trigger: NewRIOListener -> bind() where u.tx.Open() fails: winrio.CreateCompletionQueue for the tx side returns an OS error (resource limits, invalid parameters, RIO unavailable).

Common situations: Same environments as rx.Open failures - non-paged pool exhaustion, per-process RIO completion queue limits reached, antivirus/kernel network filter drivers rejecting RIO registration.

Related errors


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