slackhq/nebula · critical

unable to open socket: %w

Error message

unable to open socket: %w

What it means

NewListener wraps the raw errno from unix.Socket(AF_INET/AF_INET6, SOCK_DGRAM, IPPROTO_UDP) when the kernel refuses to create a UDP socket. The library throws it because without a raw fd it cannot build its StdConn UDP listener at all. The wrapped err is the syscall errno (e.g. EMFILE, ENFILE, EAFNOSUPPORT, EPROTONOSUPPORT).

Source

Thrown at udp/udp_linux.go:48

	// udp_linux_writebatch.go.
	bw *batchWriter

	groSupported bool
}

func NewListener(l *slog.Logger, s Settings) (Conn, error) {
	af := unix.AF_INET6
	if s.Listen.Addr().Is4() {
		af = unix.AF_INET
	}
	syscall.ForkLock.RLock()
	fd, err := unix.Socket(af, unix.SOCK_DGRAM, unix.IPPROTO_UDP)
	if err == nil {
		unix.CloseOnExec(fd)
	}
	syscall.ForkLock.RUnlock()
	if err != nil {
		return nil, fmt.Errorf("unable to open socket: %w", err)
	}

	if s.Multi {
		if err = unix.SetsockoptInt(fd, unix.SOL_SOCKET, unix.SO_REUSEPORT, 1); err != nil {
			_ = unix.Close(fd)
			return nil, fmt.Errorf("unable to set SO_REUSEPORT: %w", err)
		}
	}

	var sa unix.Sockaddr
	port := int(s.Listen.Port())
	if s.Listen.Addr().Is4() {
		sa4 := &unix.SockaddrInet4{Port: port}
		sa4.Addr = s.Listen.Addr().As4()
		sa = sa4
	} else {
		sa6 := &unix.SockaddrInet6{Port: port}
		sa6.Addr = s.Listen.Addr().As16()

View on GitHub (pinned to dd8f660c0a)

Solutions

  1. Raise the process/file-descriptor limit (ulimit -n, systemd LimitNOFILE, container rlimit) and restart
  2. Check the wrapped errno in the error chain (errors.Unwrap / %w) to identify the exact syscall failure
  3. Verify the container/runtime seccomp profile permits socket(AF_INET*, SOCK_DGRAM)
  4. Confirm the kernel supports the requested address family (IPv4 vs IPv6) and UDP protocol

Example fix

// before (shell)
ulimit -n  # 256, too low
// after (systemd unit)
[Service]
LimitNOFILE=65535
Defensive patterns

Strategy: try-catch

Validate before calling

// pre-flight: ensure fd headroom before starting nebula
n, err := syscall.Getrlimit(syscall.RLIMIT_NOFILE)
if err == nil && n.Cur < 1024 {
    return fmt.Errorf("RLIMIT_NOFILE too low (%d); raise it before starting", n.Cur)
}

Try / catch

l, err := udp.NewListener(...)
if err != nil {
    var errno syscall.Errno
    if errors.As(err, &errno) && (errors.Is(errno, syscall.EMFILE) || errors.Is(errno, syscall.ENFILE)) {
        // raise RLIMIT_NOFILE / retry after freeing fds
    }
    return fmt.Errorf("udp listener: %w", err)
}

Prevention

When it happens

Trigger: Calling udp.NewListener (directly or via nebula's interface setup) when the process is out of file descriptors (EMFILE/ENFILE), the address family is unavailable, or UDP sockets are blocked by the kernel/container seccomp profile.

Common situations: Containers with a low ulimit -n; Kubernetes pods hitting the node-wide file-descriptor cap; hardened seccomp/AppArmor policies blocking socket(2); kernels built without UDP/IPv6 support.

Related errors


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