{"record":{"id":"56c88144d7fab4de","repo":"netbirdio/netbird","slug":"failed-to-remove-interface-s-w-s","errorCode":null,"errorMessage":"failed to remove interface %s: %w - %s","messagePattern":"failed to remove interface (.+?): %w - (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"client/iface/iface_destroy_bsd.go","lineNumber":13,"sourceCode":"//go:build darwin || dragonfly || freebsd || netbsd || openbsd\n\npackage iface\n\nimport (\n\t\"fmt\"\n\t\"os/exec\"\n)\n\nfunc (w *WGIface) Destroy() error {\n\tout, err := exec.Command(\"ifconfig\", w.Name(), \"destroy\").CombinedOutput()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to remove interface %s: %w - %s\", w.Name(), err, out)\n\t}\n\n\treturn nil\n}\n","sourceCodeStart":1,"sourceCodeEnd":18,"githubUrl":"https://github.com/netbirdio/netbird/blob/93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c/client/iface/iface_destroy_bsd.go#L1-L18","documentation":"The BSD (darwin/dragonfly/freebsd/netbsd/openbsd) implementation of WGIface.Destroy() runs `ifconfig <name> destroy` and wraps failure with both the exec error and the raw combined output for diagnosis. It fails when the interface does not exist, is busy, or the process lacks privileges; note this path uses raw exec on all BSDs including macOS, not the freebsd Link helper.","triggerScenarios":"Close()'s fallback after waitUntilRemoved() timed out; destroying an interface that already vanished; running the daemon unprivileged; interface still referenced by routes or bridge membership.","commonSituations":"macOS agent where the interface already disappeared; double teardown; stale interface held by addresses or routes.","solutions":["Run the same command by hand to see the exact refusal: `sudo ifconfig <name> destroy`","Treat a missing interface as success in the caller","Ensure the daemon runs privileged","Clear addresses/routes on the interface before destroying"],"exampleFix":"// before\nfunc (w *WGIface) Destroy() error {\n    out, err := exec.Command(\"ifconfig\", w.Name(), \"destroy\").CombinedOutput()\n    if err != nil {\n        return fmt.Errorf(\"failed to remove interface %s: %w - %s\", w.Name(), err, out)\n    }\n    return nil\n}\n\n// after: idempotent destroy\nfunc (w *WGIface) Destroy() error {\n    if _, lerr := net.InterfaceByName(w.Name()); lerr != nil {\n        return nil // already gone\n    }\n    out, err := exec.Command(\"ifconfig\", w.Name(), \"destroy\").CombinedOutput()\n    if err != nil {\n        return fmt.Errorf(\"failed to remove interface %s: %w - %s\", w.Name(), err, out)\n    }\n    return nil\n}","handlingStrategy":"try-catch","validationCode":"if _, err := net.InterfaceByName(name); err != nil {\n    return nil // nothing to destroy\n}","typeGuard":null,"tryCatchPattern":"if err := w.Destroy(); err != nil {\n    if _, lerr := net.InterfaceByName(w.Name()); lerr != nil {\n        return nil // gone: success\n    }\n    return err\n}","preventionTips":["Make destroy idempotent by checking existence first","Read the embedded ifconfig output in the message: it names the real refusal","Run netbird down before manual interface surgery"],"tags":["go","bsd","macos","ifconfig","teardown"],"backgroundTag":null,"analyzedSha":"93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c","analyzedAt":"2026-08-16T03:09:19.136Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}