netbirdio/netbird · error
link by name: %w
Error message
link by name: %w
What it means
During linux wgLink.recreate(), netlink.LinkByName(name) failed with an error other than netlink.LinkNotFoundError, which the type-switch tolerates as 'does not exist, will create'. So this wrap is reserved for unexpected rtnetlink failures: permission errors, socket problems, or protocol-level errors. Note the code type-switches on the error instead of errors.As, but the semantics are 'lookup broke', not 'interface missing'.
Source
Thrown at client/iface/device/wg_link_linux.go:55
return "wireguard"
}
// Close deletes the link interface
func (l *wgLink) Close() error {
return netlink.LinkDel(l)
}
func (l *wgLink) recreate() error {
name := l.attrs.Name
// check if interface exists
link, err := netlink.LinkByName(name)
if err != nil {
switch err.(type) {
case netlink.LinkNotFoundError:
break
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)
}View on GitHub (pinned to 93e97f4bf1)
Solutions
- Run with root/CAP_NET_ADMIN
- Inspect the wrapped errno to identify the specific netlink failure
- Retry once; transient rtnetlink errors occur during interface churn
- Check whether another process deletes interfaces at that moment
Example fix
// before
switch err.(type) {
case netlink.LinkNotFoundError:
break
default:
return fmt.Errorf("link by name: %w", err)
}
// after
var lnf netlink.LinkNotFoundError
if errors.As(err, &lnf) {
// interface absent: proceed to create
} else if err != nil {
return fmt.Errorf("link by name: %w", err)
} Defensive patterns
Strategy: try-catch
Validate before calling
// pre-flight: privileges and netlink availability
if os.Geteuid() != 0 {
log.Warn("netlink operations require root or CAP_NET_ADMIN")
} Type guard
var linkNotFound netlink.LinkNotFoundError
if errors.As(err, &linkNotFound) {
// benign: interface absent, recreate will create it
} else if err != nil {
// real netlink failure (permission, protocol)
} Try / catch
if _, err := netlink.LinkByName(name); err != nil {
var lnf netlink.LinkNotFoundError
if !errors.As(err, &lnf) {
return fmt.Errorf("link by name: %w", err) // unexpected netlink failure
}
// not found: proceed to create
} Prevention
- Run with CAP_NET_ADMIN for all rtnetlink operations
- Distinguish LinkNotFoundError from real netlink errors with errors.As
- Retry once on transient rtnetlink errors during interface churn
When it happens
Trigger: Running without CAP_NET_ADMIN (EPERM on the netlink operation), netlink socket exhaustion, transient rtnetlink errors during heavy interface churn, udev/NetworkManager races.
Common situations: Agent started as an unprivileged user, containers missing NET_ADMIN, early boot before rtnetlink is fully settled.
Related errors
- create ipset: %w
- create ipset %s: %w
- add IP to ipset %s: %w
- failed to delete link %s: %w
- failed to check rule: %w
AI-assisted analysis of netbirdio/netbird@93e97f4bf1 (2026-08-16).
Data as JSON: /api/errors/b12101bd137b3264.
Report an issue: GitHub.