slackhq/nebula · error

failed to get tun address list: %s

Error message

failed to get tun address list: %s

What it means

Raised in tun.addIPs (called from Activate) when a netlink dump of the tun device's current address list fails with an error other than netlink.ErrDumpInterrupted. Nebula deliberately tolerates interrupted dumps (it logs a warning and proceeds with partial results), so this error means the address enumeration genuinely failed and stale addresses can't be reconciled.

Source

Thrown at overlay/tun_linux.go:418

	//add all new addresses
	for i := range newAddrs {
		//AddrReplace still adds new IPs, but if their properties change it will change them as well
		if err := netlink.AddrReplace(link, newAddrs[i]); err != nil {
			return err
		}
	}

	//iterate over remainder, remove whoever shouldn't be there
	al, err := netlink.AddrList(link, netlink.FAMILY_ALL)
	if err != nil {
		//RTM_GETADDR dumps the whole system, so any concurrent address change
		//interrupts it - including the kernel's async tentative->preferred
		//flip of an IPv6 address the AddrReplace calls above just added,
		//which makes this a race against our own setup. Partial results are
		//still returned; the worst case is a stale address surviving until
		//the next config reload, which beats failing startup over it.
		if !errors.Is(err, netlink.ErrDumpInterrupted) {
			return fmt.Errorf("failed to get tun address list: %s", err)
		}
		t.l.Warn("tun address list dump was interrupted, stale addresses may remain")
	}

	for i := range al {
		if hasNetlinkAddr(newAddrs, al[i]) {
			continue
		}
		err = netlink.AddrDel(link, &al[i])
		if err != nil {
			t.l.Error("failed to remove address from tun address list", "error", err)
		} else {
			t.l.Info("removed address not listed in cert(s)", "removed", al[i].String())
		}
	}

	return nil
}

View on GitHub (pinned to dd8f660c0a)

Solutions

  1. Check the %s error text for the netlink errno (e.g. ENOSPC, ENODEV) and fix the underlying cause.
  2. Verify the tun device still exists (ip link show <dev>) before activating; recreate if removed.
  3. Increase netlink dump buffer / reduce address count if ENOSPC is reported.
  4. Retry Activate() — transient netlink EAGAIN/interference is often temporary.
  5. Ensure the process runs with CAP_NET_ADMIN so netlink dumps are permitted.
Defensive patterns

Strategy: retry

Validate before calling

link, err := netlink.LinkByName(dev)
if err != nil { return fmt.Errorf("tun %s missing before activate: %w", dev, err) }
if _, err := netlink.AddrList(link, netlink.FAMILY_ALL); err != nil {
    return fmt.Errorf("netlink addr dump unavailable: %w", err)
}

Try / catch

if err := activate(); err != nil {
    if strings.Contains(err.Error(), "failed to get tun address list") {
        time.Sleep(500 * time.Millisecond); err = activate() // one retry
    }
}

Prevention

When it happens

Trigger: Calling Activate() when netlink.AddrList (or equivalent dump) on the tun link returns a non-ErrDumpInterrupted error — e.g. the link disappeared, netlink socket errors, or permission problems.

Common situations: Race where the tun device was removed/recreated mid-activation; netlink buffer too small (ENOSPC) for many addresses; restricted environments (some sandboxes) blocking netlink RTM_GETADDR dumps.

Related errors


AI-assisted analysis of slackhq/nebula@dd8f660c0a (2026-09-03). Data as JSON: /api/errors/b8a429dacf93aa59. Report an issue: GitHub.