netbirdio/netbird · error

failed to remove interface %s: %w - %s

Error message

failed to remove interface %s: %w - %s

What it means

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.

Source

Thrown at client/iface/iface_destroy_bsd.go:13

//go:build darwin || dragonfly || freebsd || netbsd || openbsd

package iface

import (
	"fmt"
	"os/exec"
)

func (w *WGIface) Destroy() error {
	out, err := exec.Command("ifconfig", w.Name(), "destroy").CombinedOutput()
	if err != nil {
		return fmt.Errorf("failed to remove interface %s: %w - %s", w.Name(), err, out)
	}

	return nil
}

View on GitHub (pinned to 93e97f4bf1)

Solutions

  1. Run the same command by hand to see the exact refusal: `sudo ifconfig <name> destroy`
  2. Treat a missing interface as success in the caller
  3. Ensure the daemon runs privileged
  4. Clear addresses/routes on the interface before destroying

Example fix

// before
func (w *WGIface) Destroy() error {
    out, err := exec.Command("ifconfig", w.Name(), "destroy").CombinedOutput()
    if err != nil {
        return fmt.Errorf("failed to remove interface %s: %w - %s", w.Name(), err, out)
    }
    return nil
}

// after: idempotent destroy
func (w *WGIface) Destroy() error {
    if _, lerr := net.InterfaceByName(w.Name()); lerr != nil {
        return nil // already gone
    }
    out, err := exec.Command("ifconfig", w.Name(), "destroy").CombinedOutput()
    if err != nil {
        return fmt.Errorf("failed to remove interface %s: %w - %s", w.Name(), err, out)
    }
    return nil
}
Defensive patterns

Strategy: try-catch

Validate before calling

if _, err := net.InterfaceByName(name); err != nil {
    return nil // nothing to destroy
}

Try / catch

if err := w.Destroy(); err != nil {
    if _, lerr := net.InterfaceByName(w.Name()); lerr != nil {
        return nil // gone: success
    }
    return err
}

Prevention

When it happens

Trigger: 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.

Common situations: macOS agent where the interface already disappeared; double teardown; stale interface held by addresses or routes.

Related errors


AI-assisted analysis of netbirdio/netbird@93e97f4bf1 (2026-08-16). Data as JSON: /api/errors/56c88144d7fab4de. Report an issue: GitHub.