netbirdio/netbird · error

received error "%w" while configuring interface %s with port

Error message

received error "%w" while configuring interface %s with port %d

What it means

The kernel WireGuard configurer failed to apply the device-level configuration (private key, fwmark, listen port) through wgctrl/netlink on the named interface. The %w chain carries the underlying cause, which in practice is syscall.ENOENT when the interface disappeared, EACCES/EPERM without CAP_NET_ADMIN or root, EADDRINUSE when the listen port is taken, or EINVAL for a bad key/fwmark. The message deliberately names the interface and port because the same error covers several distinct root causes.

Source

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

}

func (c *KernelConfigurer) ConfigureInterface(privateKey string, port int) error {
	log.Debugf("adding Wireguard private key")
	key, err := wgtypes.ParseKey(privateKey)
	if err != nil {
		return err
	}
	fwmark := getFwmark()
	config := wgtypes.Config{
		PrivateKey:   &key,
		ReplacePeers: true,
		FirewallMark: &fwmark,
		ListenPort:   &port,
	}

	err = c.configure(config)
	if err != nil {
		return fmt.Errorf(`received error "%w" while configuring interface %s with port %d`, err, c.deviceName, port)
	}
	return nil
}

// SetPresharedKey sets the preshared key for a peer.
// If updateOnly is true, only updates the existing peer; if false, creates or updates.
func (c *KernelConfigurer) SetPresharedKey(peerKey string, psk wgtypes.Key, updateOnly bool) error {
	parsedPeerKey, err := wgtypes.ParseKey(peerKey)
	if err != nil {
		return err
	}

	cfg := buildPresharedKeyConfig(parsedPeerKey, psk, updateOnly)
	return c.configure(cfg)
}

func (c *KernelConfigurer) UpdatePeer(peerKey string, allowedIps []netip.Prefix, keepAlive time.Duration, endpoint *net.UDPAddr, preSharedKey *wgtypes.Key) error {
	peerKeyParsed, err := wgtypes.ParseKey(peerKey)

View on GitHub (pinned to 93e97f4bf1)

Solutions

  1. Check the wrapped syscall: ENOENT means recreate the interface first; EACCES means run privileged; EADDRINUSE means change the port or free it
  2. Verify the agent runs as root or with CAP_NET_ADMIN (container: --cap-add NET_ADMIN)
  3. Ensure only one agent instance manages the interface and previous runs fully tore it down (netbird down / ip link del)
  4. Retry the configure once after recreating the interface when the cause is the teardown race
  5. On port conflicts, let NetBird pick an ephemeral port instead of pining ListenPort

Example fix

// before
if err := c.Configure(key, port); err != nil { return err }

// after
if err := c.Configure(key, port); err != nil {
    if errors.Is(err, syscall.ENOENT) {
        // interface vanished; caller recreates it and retries once
        return fmt.Errorf("interface %s gone, recreate: %w", c.deviceName, err)
    }
    return err
}
Defensive patterns

Strategy: try-catch

Validate before calling

// before configuring, confirm privileges and interface presence
if os.Geteuid() != 0 {
    return errors.New("kernel WireGuard configuration requires root")
}
if _, err := net.InterfaceByName(ifaceName); err != nil {
    return fmt.Errorf("interface missing, recreate first: %w", err)
}

Type guard

func kernelWGReady(name string) bool {
    if _, err := net.InterfaceByName(name); err != nil {
        return false
    }
    client, err := wgctrl.New()
    if err != nil {
        return false
    }
    defer client.Close()
    _, err = client.Device(name)
    return err == nil
}

Try / catch

if err := configurer.ConfigureInterface(key, port); err != nil {
    switch {
    case errors.Is(err, syscall.ENOENT):
        // recreate interface and retry once
    case errors.Is(err, syscall.EADDRINUSE):
        // pick a different listen port
    case errors.Is(err, syscall.EACCES), errors.Is(err, syscall.EPERM):
        return fmt.Errorf("need root/CAP_NET_ADMIN: %w", err)
    default:
        return err
    }
}

Prevention

When it happens

Trigger: The interface was deleted between creation and configuration (race with teardown or external ip link del); agent not running as root or missing CAP_NET_ADMIN; the requested ListenPort already bound by another process; wgctrl kernel socket unavailable in restricted containers/seccomp profiles.

Common situations: Running netbird without privileges or in a container lacking NET_ADMIN; another WireGuard instance or the previous unclean shutdown still holding the port; platform uapi/wgctrl regressions after kernel or package upgrades; interface churn during rapid up/down cycles.

Related errors


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