netbirdio/netbird · error

failed to delete link %s: %w

Error message

failed to delete link %s: %w

What it means

The second half of Linux Destroy(): after the link is resolved, netlink.LinkDel asks the kernel to delete it and this error wraps the failure. Causes: insufficient privilege (EPERM without CAP_NET_ADMIN), the link being busy or referenced (EBUSY), a link type the kernel refuses to delete, or transient netlink socket errors.

Source

Thrown at client/iface/iface_destroy_linux.go:18

//go:build linux && !android

package iface

import (
	"fmt"

	"github.com/vishvananda/netlink"
)

func (w *WGIface) Destroy() error {
	link, err := netlink.LinkByName(w.Name())
	if err != nil {
		return fmt.Errorf("failed to get link by name %s: %w", w.Name(), err)
	}

	if err := netlink.LinkDel(link); err != nil {
		return fmt.Errorf("failed to delete link %s: %w", w.Name(), err)
	}

	return nil
}

View on GitHub (pinned to 93e97f4bf1)

Solutions

  1. Run `sudo ip link del <name>` to surface the exact errno
  2. Clear routes and firewall references to the interface, then retry
  3. Grant CAP_NET_ADMIN or run the daemon as root
  4. If the kernel keeps refusing (EBUSY), reboot is the last resort
Defensive patterns

Strategy: retry

Try / catch

if err := w.Destroy(); err != nil {
    if _, lerr := net.InterfaceByName(w.Name()); lerr == nil {
        // still present: transient refusal (EBUSY-class), retry once
        err = w.Destroy()
    }
    return err
}

Prevention

When it happens

Trigger: LinkDel returning EPERM/EBUSY/EINVAL: unprivileged daemon, interface still referenced by routes or firewall rules, or a halfway-removed interface during rapid up/down cycling.

Common situations: Containers with trimmed capabilities; external network daemons re-referencing the interface; repeated teardown/setup cycles racing kernel cleanup.

Related errors


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