netbirdio/netbird · error
timeout when waiting for interface %s to be removed
Error message
timeout when waiting for interface %s to be removed
What it means
waitUntilRemoved() polls net.InterfaceByName every 100ms for up to 5 seconds and succeeds when the interface disappears (lookup fails with *net.OpError or returns nil). This error means the 5s deadline passed with the interface still present, or with InterfaceByName returning an error type the loop does not recognize as removal; Close() then falls back to Destroy().
Source
Thrown at client/iface/iface.go:346
timeout := time.NewTimer(maxWaitTime)
defer timeout.Stop()
for {
iface, err := net.InterfaceByName(w.Name())
if err != nil {
if _, ok := err.(*net.OpError); ok {
log.Infof("interface %s has been removed", w.Name())
return nil
}
log.Debugf("failed to get interface by name %s: %v", w.Name(), err)
} else if iface == nil {
log.Infof("interface %s has been removed", w.Name())
return nil
}
select {
case <-timeout.C:
return fmt.Errorf("timeout when waiting for interface %s to be removed", w.Name())
default:
time.Sleep(100 * time.Millisecond)
}
}
}
// GetNet returns the netstack.Net for the netstack device
func (w *WGIface) GetNet() *netstack.Net {
w.mu.Lock()
defer w.mu.Unlock()
return w.tun.GetNet()
}
View on GitHub (pinned to 93e97f4bf1)
Solutions
- Check what keeps the interface alive: `ip link show <name>` plus routes and firewall references
- Let Close()'s fallback Destroy() run; read its error if it also fails
- Remove manually (`ip link del`, `ifconfig destroy`, netsh) once the holder is cleared
- Wait for full teardown to finish before recreating the interface
Defensive patterns
Strategy: retry
Validate before calling
deadline := time.Now().Add(10 * time.Second)
for time.Now().Before(deadline) {
if _, err := net.InterfaceByName(name); err != nil {
return nil // removed
}
time.Sleep(200 * time.Millisecond)
}
return fmt.Errorf("interface %s still present after extended wait", name) Prevention
- Wait for full teardown to complete before recreating an interface
- Remove routes, addresses, and firewall references during teardown so the kernel can release the link
- Treat the 5s poll timeout as a symptom of a holder, not of slowness
When it happens
Trigger: Kernel interface still listed after tun.Close(): leftover routes or addresses keep it referenced, another process holds or recreates it, or a loaded host is slow to release it.
Common situations: Rapid down/up cycles; network management daemons re-adding the interface; zombie interfaces after unclean shutdowns.
Understand the failure class
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- failed to remove WireGuard interface %s: %w
- session_idle_timeout must be positive for L4 services
- request_timeout must be positive for L4 services
- dial context: %w
- link by name: %w
AI-assisted analysis of netbirdio/netbird@93e97f4bf1 (2026-08-16).
Data as JSON: /api/errors/234e1058de0ba722.
Report an issue: GitHub.