{"record":{"id":"234e1058de0ba722","repo":"netbirdio/netbird","slug":"timeout-when-waiting-for-interface-s-to-be-remove","errorCode":null,"errorMessage":"timeout when waiting for interface %s to be removed","messagePattern":"timeout when waiting for interface (.+?) to be removed","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"client/iface/iface.go","lineNumber":346,"sourceCode":"\ttimeout := time.NewTimer(maxWaitTime)\n\tdefer timeout.Stop()\n\n\tfor {\n\t\tiface, err := net.InterfaceByName(w.Name())\n\t\tif err != nil {\n\t\t\tif _, ok := err.(*net.OpError); ok {\n\t\t\t\tlog.Infof(\"interface %s has been removed\", w.Name())\n\t\t\t\treturn nil\n\t\t\t}\n\t\t\tlog.Debugf(\"failed to get interface by name %s: %v\", w.Name(), err)\n\t\t} else if iface == nil {\n\t\t\tlog.Infof(\"interface %s has been removed\", w.Name())\n\t\t\treturn nil\n\t\t}\n\n\t\tselect {\n\t\tcase <-timeout.C:\n\t\t\treturn fmt.Errorf(\"timeout when waiting for interface %s to be removed\", w.Name())\n\t\tdefault:\n\t\t\ttime.Sleep(100 * time.Millisecond)\n\t\t}\n\t}\n}\n\n// GetNet returns the netstack.Net for the netstack device\nfunc (w *WGIface) GetNet() *netstack.Net {\n\tw.mu.Lock()\n\tdefer w.mu.Unlock()\n\n\treturn w.tun.GetNet()\n}\n","sourceCodeStart":328,"sourceCodeEnd":360,"githubUrl":"https://github.com/netbirdio/netbird/blob/93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c/client/iface/iface.go#L328-L360","documentation":"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().","triggerScenarios":"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.","commonSituations":"Rapid down/up cycles; network management daemons re-adding the interface; zombie interfaces after unclean shutdowns.","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"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"deadline := time.Now().Add(10 * time.Second)\nfor time.Now().Before(deadline) {\n    if _, err := net.InterfaceByName(name); err != nil {\n        return nil // removed\n    }\n    time.Sleep(200 * time.Millisecond)\n}\nreturn fmt.Errorf(\"interface %s still present after extended wait\", name)","typeGuard":null,"tryCatchPattern":null,"preventionTips":["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"],"tags":["go","netbird","interface","teardown","timeout"],"backgroundTag":null,"analyzedSha":"93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c","analyzedAt":"2026-08-16T03:09:19.136Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}