netbirdio/netbird · error

converting file to packet conn failed: %w

Error message

converting file to packet conn failed: %w

What it means

Returned by rawsocket.prepareSenderRawSocket when net.FilePacketConn(file) fails. FilePacketConn duplicates the fd with dup() and requires the fd to actually be a packet socket; failure is almost always EMFILE/ENFILE (fd exhaustion at the dup) or, if the fd was somehow closed in between, EBADF/ENOTSOCK. The raw socket is required (IPv4) for the eBPF proxy and the SrcFaker, so Listen()/NewSrcFaker aborts.

Source

Thrown at client/iface/wgproxy/rawsocket/rawsocket.go:85

			log.Warnf("failed to close raw socket fd: %v", closeErr)
		}
		return nil, fmt.Errorf("setting fwmark failed: %w", err)
	}

	// Convert the file descriptor to a PacketConn.
	file := os.NewFile(uintptr(fd), fmt.Sprintf("fd %d", fd))
	if file == nil {
		if closeErr := syscall.Close(fd); closeErr != nil {
			log.Warnf("failed to close raw socket fd: %v", closeErr)
		}
		return nil, fmt.Errorf("converting fd to file failed")
	}
	packetConn, err := net.FilePacketConn(file)
	if err != nil {
		if closeErr := file.Close(); closeErr != nil {
			log.Warnf("failed to close file: %v", closeErr)
		}
		return nil, fmt.Errorf("converting file to packet conn failed: %w", err)
	}

	// Close the original file to release the FD (net.FilePacketConn duplicates it)
	if closeErr := file.Close(); closeErr != nil {
		log.Warnf("failed to close file after creating packet conn: %v", closeErr)
	}

	return packetConn, nil
}

View on GitHub (pinned to 93e97f4bf1)

Solutions

  1. Check and raise the fd limit: `ulimit -n` / `systemctl edit netbird` with LimitNOFILE=65536, or `--ulimit nofile=65536:65536` for containers
  2. Count the agent's fds: `ls /proc/$(pgrep -x netbird)/fd | wc -l` - steady growth indicates the SrcFaker sockets are not being closed
  3. Restart the agent to recover immediately once limits are raised
  4. If not fd exhaustion, read the wrapped errno from the %w chain: ENOTSOCK means the fd was already closed elsewhere
Defensive patterns

Strategy: validation

Validate before calling

// fd headroom check before opening raw sockets
func fdHeadroom(want int) bool {
    var lim syscall.Rlimit
    if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &lim); err != nil {
        return true
    }
    used := 0
    if ents, err := os.ReadDir("/proc/self/fd"); err == nil {
        used = len(ents)
    }
    return uint64(used+want) < lim.Cur
}

Try / catch

if _, err := net.FilePacketConn(file); err != nil {
    if errors.Is(err, syscall.EMFILE) || errors.Is(err, syscall.ENFILE) {
        log.Errorf("fd limit reached; raise ulimit -n: %v", err)
    }
    return fmt.Errorf("packet conn: %w", err)
}

Prevention

When it happens

Trigger: Process at its open-file limit when creating the raw socket - common in the UDP proxy path where each peer redirect (RedirectAs -> NewSrcFaker) opens one raw socket; long-lived agents with many relays/peers leaking fds; low `ulimit -n` in containers or systemd unit.

Common situations: Agents with many peers churning direct/relay paths over days; container defaults of 1024 fds; other software on the host inflating the fd count; leaks from previous failed NewSrcFaker paths.

Related errors


AI-assisted analysis of netbirdio/netbird@93e97f4bf1 (2026-08-16). Data as JSON: /api/errors/32b3883a192345cf. Report an issue: GitHub.