slackhq/nebula · error
failed to get tun device link: %s
Error message
failed to get tun device link: %s
What it means
Raised in tun.Activate when netlink.LinkByName(t.Device) cannot find the tun device's link. Nebula needs the link to read its interface index (deviceIndex) for subsequent route setup. It means the kernel has no link registered under the configured device name.
Source
Thrown at overlay/tun_linux.go:463
s, err := unix.Socket(
unix.AF_INET, //because everything we use t.ioctlFd for is address family independent, this is fine
unix.SOCK_DGRAM,
unix.IPPROTO_IP,
)
if err != nil {
return err
}
t.ioctlFd = uintptr(s)
// Set the device name
ifrf := ifReq{Name: devName}
if err = ioctl(t.ioctlFd, unix.SIOCGIFFLAGS, uintptr(unsafe.Pointer(&ifrf))); err != nil {
return fmt.Errorf("failed to set tun device name: %s", err)
}
link, err := netlink.LinkByName(t.Device)
if err != nil {
return fmt.Errorf("failed to get tun device link: %s", err)
}
t.deviceIndex = link.Attrs().Index
// Setup our default MTU
t.setMTU()
// Set the transmit queue length
ifrq := ifreqQLEN{Name: devName, Value: int32(t.TXQueueLen)}
if err = ioctl(t.ioctlFd, unix.SIOCSIFTXQLEN, uintptr(unsafe.Pointer(&ifrq))); err != nil {
// If we can't set the queue length nebula will still work but it may lead to packet loss
t.l.Error("Failed to set tun tx queue length", "error", err)
}
const modeNone = 1
if err = netlink.LinkSetIP6AddrGenMode(link, modeNone); err != nil {
t.l.Warn("Failed to disable link local address generation", "error", err)
}View on GitHub (pinned to dd8f660c0a)
Solutions
- Confirm the device name: run ip link and compare with tun.dev config; fix the config typo.
- Ensure the tun kernel module is loaded (modprobe tun) and /dev/net/tun exists.
- Prevent external daemons (NetworkManager, systemd-networkd) from deleting the interface (mark it unmanaged).
- Recreate the tun device and retry Activate().
Example fix
// before (config) tun.dev: tun9 // after — name must match the created device # ip link -> device is tun0 tun.dev: tun0
Defensive patterns
Strategy: validation
Validate before calling
func linkExists(name string) bool {
_, err := netlink.LinkByName(name)
return err == nil
}
// call before Activate: if !linkExists(t.Device) { recreate tun } Try / catch
if err := t.Activate(netstack); err != nil {
if strings.Contains(err.Error(), "failed to get tun device link") {
log.Error("tun link missing — check tun.dev and kernel tun module", "cause", err)
}
} Prevention
- Load the tun kernel module (modprobe tun) at boot
- Cross-check tun.dev against `ip link` output
- Block external daemons from deleting the interface
- Compare name spelling exactly (tun0 vs tun9)
When it happens
Trigger: Calling Activate() when the tun interface named by t.Device doesn't exist in the kernel's link table — the TUNSETIFF/dev attach didn't register it, or it was removed.
Common situations: Config typo in tun.dev; device deleted by another process or network manager before activation; using a name not matching the created device; kernel without tun module loaded (tun not in /dev).
Related errors
- failed to get tun address list: %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/049d367aa7aac371.
Report an issue: GitHub.