netbirdio/netbird · error
failed to remove WireGuard interface %s: %w
Error message
failed to remove WireGuard interface %s: %w
What it means
Emitted at the end of WGIface.Close() when waitUntilRemoved() timed out (interface still listed after 5 seconds of 100ms polling) and the forced w.Destroy() that follows also failed. It is a compounded teardown failure: neither graceful removal nor the platform-specific destroy cleared the interface, so it outlives the agent process.
Source
Thrown at client/iface/iface.go:240
// wireguard-go device.Close() waits for its send/receive goroutines
// to drain. Some of those goroutines re-enter WGIface methods that
// take w.mu (e.g. the packet filter DNS hook calls GetDevice()), so
// holding the mutex here would deadlock the shutdown path.
tun := w.tun
w.mu.Unlock()
if err := tun.Close(); err != nil {
result = multierror.Append(result, fmt.Errorf("failed to close wireguard interface %s: %w", w.Name(), err))
}
if nbnetstack.IsEnabled() {
return errors.FormatErrorOrNil(result)
}
if err := w.waitUntilRemoved(); err != nil {
log.Warnf("failed to remove WireGuard interface %s: %v", w.Name(), err)
if err := w.Destroy(); err != nil {
result = multierror.Append(result, fmt.Errorf("failed to remove WireGuard interface %s: %w", w.Name(), err))
return errors.FormatErrorOrNil(result)
}
log.Infof("interface %s successfully removed", w.Name())
}
return errors.FormatErrorOrNil(result)
}
// SetFilter sets packet filters for the userspace implementation
func (w *WGIface) SetFilter(filter device.PacketFilter) error {
w.mu.Lock()
defer w.mu.Unlock()
if w.tun.FilteredDevice() == nil {
return fmt.Errorf("userspace packet filtering not handled on this device")
}
w.filter = filterView on GitHub (pinned to 93e97f4bf1)
Solutions
- Identify the holder: `ip link show <name>` / `ifconfig <name>` / `netsh interface show interface`, plus routes referencing it
- Remove manually: `sudo ip link del <name>` (Linux), `sudo ifconfig <name> destroy` (BSD), adapter removal in Device Manager (Windows)
- Fix the underlying Destroy() failure using its own error message (wrapped in this chain)
- Reboot the host if the kernel refuses all removal
Defensive patterns
Strategy: fallback
Validate before calling
if _, err := net.InterfaceByName(name); err == nil {
// still present after Close: fall back to platform-specific destroy
if err := destroyInterface(name); err != nil {
log.Warnf("manual cleanup required for %s: %v", name, err)
}
} Prevention
- Always run netbird down before stopping or rebuilding the daemon
- Never let two agents manage the same interface name
- Clean zombie interfaces before the next netbird up
When it happens
Trigger: Kernel-mode interface lingering because routes, addresses, or another process still reference it, combined with Destroy() failing for its own per-OS reason (ifconfig destroy / netlink LinkDel / netsh); only reached when netstack is disabled.
Common situations: Rapid up/down cycles leaving zombie interfaces; external network or firewall daemons holding references; degraded environments where the destroy command cannot execute.
Related errors
- timeout when waiting for interface %s to be removed
- ICEBind has not been initialized yet
- received error "%w" while configuring interface %s with port
- received error "%w" while updating peer on interface %s with
- get peer: %w
AI-assisted analysis of netbirdio/netbird@93e97f4bf1 (2026-08-16).
Data as JSON: /api/errors/0b0234d0de1f1a7c.
Report an issue: GitHub.