{"record":{"id":"049d367aa7aac371","repo":"slackhq/nebula","slug":"failed-to-get-tun-device-link-s","errorCode":null,"errorMessage":"failed to get tun device link: %s","messagePattern":"failed to get tun device link: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"overlay/tun_linux.go","lineNumber":463,"sourceCode":"\ts, err := unix.Socket(\n\t\tunix.AF_INET, //because everything we use t.ioctlFd for is address family independent, this is fine\n\t\tunix.SOCK_DGRAM,\n\t\tunix.IPPROTO_IP,\n\t)\n\tif err != nil {\n\t\treturn err\n\t}\n\tt.ioctlFd = uintptr(s)\n\n\t// Set the device name\n\tifrf := ifReq{Name: devName}\n\tif err = ioctl(t.ioctlFd, unix.SIOCGIFFLAGS, uintptr(unsafe.Pointer(&ifrf))); err != nil {\n\t\treturn fmt.Errorf(\"failed to set tun device name: %s\", err)\n\t}\n\n\tlink, err := netlink.LinkByName(t.Device)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to get tun device link: %s\", err)\n\t}\n\n\tt.deviceIndex = link.Attrs().Index\n\n\t// Setup our default MTU\n\tt.setMTU()\n\n\t// Set the transmit queue length\n\tifrq := ifreqQLEN{Name: devName, Value: int32(t.TXQueueLen)}\n\tif err = ioctl(t.ioctlFd, unix.SIOCSIFTXQLEN, uintptr(unsafe.Pointer(&ifrq))); err != nil {\n\t\t// If we can't set the queue length nebula will still work but it may lead to packet loss\n\t\tt.l.Error(\"Failed to set tun tx queue length\", \"error\", err)\n\t}\n\n\tconst modeNone = 1\n\tif err = netlink.LinkSetIP6AddrGenMode(link, modeNone); err != nil {\n\t\tt.l.Warn(\"Failed to disable link local address generation\", \"error\", err)\n\t}","sourceCodeStart":445,"sourceCodeEnd":481,"githubUrl":"https://github.com/slackhq/nebula/blob/dd8f660c0ac37903ec4080ca4d3c861ba9342ceb/overlay/tun_linux.go#L445-L481","documentation":"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.","triggerScenarios":"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.","commonSituations":"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).","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()."],"exampleFix":"// before (config)\ntun.dev: tun9\n// after — name must match the created device\n# ip link  -> device is tun0\ntun.dev: tun0","handlingStrategy":"validation","validationCode":"func linkExists(name string) bool {\n    _, err := netlink.LinkByName(name)\n    return err == nil\n}\n// call before Activate: if !linkExists(t.Device) { recreate tun }","typeGuard":null,"tryCatchPattern":"if err := t.Activate(netstack); err != nil {\n    if strings.Contains(err.Error(), \"failed to get tun device link\") {\n        log.Error(\"tun link missing — check tun.dev and kernel tun module\", \"cause\", err)\n    }\n}","preventionTips":["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)"],"tags":["network","tun","linux","netlink"],"backgroundTag":"link-not-found","analyzedSha":"dd8f660c0ac37903ec4080ca4d3c861ba9342ceb","analyzedAt":"2026-09-03T11:13:55.444Z","contentChangedAt":"2026-09-03T11:13:55.444Z","schemaVersion":2},"datasetVersion":"2026-09-10T17:17:09.494Z"}