netbirdio/netbird · error

wgctl: %w

Error message

wgctl: %w

What it means

KernelConfigurer.getPeer could not create a wgctrl client with wgctrl.New(). On Linux and FreeBSD wgctrl opens a netlink socket (falling back to the /dev/wg userspace protocol) to talk to the kernel WireGuard module; construction fails when the module is unavailable or the socket cannot be opened due to permissions. This happens before any device query, so every kernel-mode peer/device operation through getPeer is blocked by it.

Source

Thrown at client/iface/configurer/kernel_unix.go:220

		UpdateOnly:        true,
		ReplaceAllowedIPs: true,
		AllowedIPs:        newAllowedIPs,
	}

	config := wgtypes.Config{
		Peers: []wgtypes.PeerConfig{peer},
	}
	err = c.configure(config)
	if err != nil {
		return fmt.Errorf("remove allowed IP %s on interface %s: %w", allowedIP, c.deviceName, err)
	}
	return nil
}

func (c *KernelConfigurer) getPeer(ifaceName, peerPubKey string) (wgtypes.Peer, error) {
	wg, err := wgctrl.New()
	if err != nil {
		return wgtypes.Peer{}, fmt.Errorf("wgctl: %w", err)
	}
	defer func() {
		err = wg.Close()
		if err != nil {
			log.Errorf("Got error while closing wgctl: %v", err)
		}
	}()

	wgDevice, err := wg.Device(ifaceName)
	if err != nil {
		return wgtypes.Peer{}, fmt.Errorf("get device %s: %w", ifaceName, err)
	}
	for _, peer := range wgDevice.Peers {
		if peer.PublicKey.String() == peerPubKey {
			return peer, nil
		}
	}
	return wgtypes.Peer{}, ErrPeerNotFound

View on GitHub (pinned to 93e97f4bf1)

Solutions

  1. Load the module: sudo modprobe wireguard (and install wireguard-tools/DKMS so it persists)
  2. Run the daemon as root or with CAP_NET_ADMIN
  3. If kernel WireGuard cannot be provided, use the userspace configurer (wireguard-go device with NewUSPConfigurer) instead
  4. Probe wgctrl.New() at startup and log a clear 'kernel WireGuard unavailable' diagnostic

Example fix

// before: assume kernel WireGuard exists
kernelCfg := configurer.NewKernelConfigurer(ifaceName)

// after: probe and fall back to the userspace configurer
if _, err := wgctrl.New(); err != nil {
	log.Warnf("kernel WireGuard unavailable (%v), falling back to userspace", err)
	// build a wireguard-go device and use configurer.NewUSPConfigurer(dev, ifaceName, recorder)
}
Defensive patterns

Strategy: fallback

Validate before calling

// probe kernel WireGuard support once at startup
func kernelWgAvailable() bool {
	c, err := wgctrl.New()
	if err != nil {
		return false
	}
	defer c.Close()
	return true
}

Try / catch

wg, err := wgctrl.New()
if err != nil {
	log.Warnf("kernel WireGuard unavailable (%v); using userspace device", err)
	// construct wireguard-go device + NewUSPConfigurer instead of NewKernelConfigurer
}

Prevention

When it happens

Trigger: Kernel WireGuard module not loaded or not built into the kernel (no CONFIG_WIREGUARD); wireguard-kmod package missing on FreeBSD; process without CAP_NET_ADMIN opening the netlink socket; restrictive container or seccomp profile blocking netlink.

Common situations: Bare-metal or VM host without wireguard installed; minimal container images lacking kernel headers/modules; agent started unprivileged; custom kernels compiled without WireGuard support.

Related errors


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