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
- Check the %s error text for the netlink errno (e.g. ENOSPC, ENODEV) and fix the underlying cause.
- Verify the tun device still exists (ip link show <dev>) before activating; recreate if removed.
- Increase netlink dump buffer / reduce address count if ENOSPC is reported.
- Retry Activate() — transient netlink EAGAIN/interference is often temporary.
- 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
- Confirm the tun interface exists before activating
- Run with CAP_NET_ADMIN so netlink dumps are allowed
- Keep address counts modest to avoid netlink dump ENOSPC
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
- failed to get tun device link: %s
- failed to enable offload on multiqueue tun fd: %w
- failed to set tun device name: %s
- failed to bring the tun device up: %s
- failed to run tun device: %s
AI-assisted analysis of slackhq/nebula@dd8f660c0a (2026-09-03).
Data as JSON: /api/errors/b8a429dacf93aa59.
Report an issue: GitHub.