netbirdio/netbird · critical

link add: %w

Error message

link add: %w

What it means

netlink.LinkAdd(l) failed with an error other than EEXIST (EEXIST is tolerated with 'interface already exists, will reuse'). The link reports Type() "wireguard", so RTM_NEWLINK requires the wireguard kernel module; an unsupported kind, missing privileges, or an invalid name are the classic causes. This is the kernel-mode interface creation step and is fatal to bring-up.

Source

Thrown at client/iface/device/wg_link_linux.go:72

		default:
			return fmt.Errorf("link by name: %w", err)
		}
	}

	// remove if interface exists
	if link != nil {
		err = netlink.LinkDel(l)
		if err != nil {
			return err
		}
	}

	log.Debugf("adding device: %s", name)
	err = netlink.LinkAdd(l)
	if os.IsExist(err) {
		log.Infof("interface %s already exists. Will reuse.", name)
	} else if err != nil {
		return fmt.Errorf("link add: %w", err)
	}

	return nil
}

func (l *wgLink) setMTU(mtu int) error {
	if err := netlink.LinkSetMTU(l, mtu); err != nil {
		log.Errorf("error setting MTU on interface: %s", l.attrs.Name)

		return fmt.Errorf("link set mtu: %w", err)
	}

	return nil
}

func (l *wgLink) up() error {
	if err := netlink.LinkSetUp(l); err != nil {
		log.Errorf("error bringing up interface: %s", l.attrs.Name)

View on GitHub (pinned to 93e97f4bf1)

Solutions

  1. Load the module (modprobe wireguard) or install matching kernel modules and run depmod
  2. Run with root/CAP_NET_ADMIN
  3. Shorten the interface name to 15 bytes or fewer
  4. If the kernel cannot provide wireguard, force userspace mode with NB_WG_KERNEL_DISABLED=true or rely on the automatic userspace fallback

Example fix

// before
if err := l.recreate(); err != nil {
    return err
}

// after
if !device.WireGuardModuleIsLoaded() {
    return fmt.Errorf("kernel wireguard unavailable; run in userspace mode")
}
if err := l.recreate(); err != nil {
    return err
}
Defensive patterns

Strategy: validation

Validate before calling

if !device.WireGuardModuleIsLoaded() {
    // no kernel wireguard: use userspace mode instead of attempting LinkAdd
    return useUserspaceMode()
}
if len(ifaceName) > 15 {
    return fmt.Errorf("interface name %q exceeds 15 bytes", ifaceName)
}

Try / catch

if err := netlink.LinkAdd(l); err != nil && !os.IsExist(err) {
    if errors.Is(err, syscall.EPERM) {
        // missing CAP_NET_ADMIN
    } else if errors.Is(err, syscall.EPROTONOSUPPORT) || errors.Is(err, syscall.EOPNOTSUPP) {
        // wireguard kind unsupported: module missing
    }
    return fmt.Errorf("link add: %w", err)
}

Prevention

When it happens

Trigger: wireguard module unavailable (unsupported kind error), EPERM without CAP_NET_ADMIN, EINVAL for a name over 15 bytes or invalid attributes, ENOMEM/ENFILE at the interface limit.

Common situations: Old or custom kernels without wireguard, stripped module sets in minimal images, overlong interface names, kernel/userspace mode selection picking kernel mode on an unsupported host.

Related errors


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