slackhq/nebula · error
failed to enable offload on multiqueue tun fd: %w
Error message
failed to enable offload on multiqueue tun fd: %w
What it means
This error is returned by tun.addQueue when creating a multiqueue tun device: the TUNSETOFFLOAD ioctl that enables checksum/segmentation offload on a newly opened queue file descriptor failed. The original fd is closed and the wrapped kernel error is included via %w, so the underlying cause (e.g. EINVAL, ENOTSUP) is always embedded. It only fires when vnetHdr is true, i.e. when offload/vnet-header support was negotiated.
Source
Thrown at overlay/tun_linux.go:353
fd, err := unix.Open("/dev/net/tun", os.O_RDWR, 0)
if err != nil {
return err
}
flags := uint16(unix.IFF_TUN | unix.IFF_NO_PI | unix.IFF_MULTI_QUEUE)
if t.vnetHdr {
flags |= unix.IFF_VNET_HDR
}
if _, err = tunSetIff(fd, t.Device, flags); err != nil {
_ = unix.Close(fd)
return err
}
if t.vnetHdr {
if err = ioctl(uintptr(fd), unix.TUNSETOFFLOAD, uintptr(t.offloadFlags)); err != nil {
_ = unix.Close(fd)
return fmt.Errorf("failed to enable offload on multiqueue tun fd: %w", err)
}
}
err = t.readers.Add(fd)
if err != nil {
_ = unix.Close(fd)
return err
}
return nil
}
func (t *tun) RoutesFor(ip netip.Addr) routing.Gateways {
r, _ := t.routeTree.Load().Lookup(ip)
return r
}
func (t *tun) deviceBytes() (o [16]byte) {View on GitHub (pinned to dd8f660c0a)
Solutions
- Inspect the wrapped error (%w) with errors.Unwrap to identify the errno; EINVAL usually means unsupported offload flags.
- Update the kernel or run on a host whose tun driver supports the requested offload features.
- Run nebula with offload disabled (e.g. older tun config path or a build/config that leaves vnetHdr off) if the platform can't support it.
- Check that the process has permission to attach to the tun device (CAP_NET_ADMIN) and that the fd is valid.
Example fix
// before: opaque failure on kernels without UFO support
offloadFlags := unix.TUNSETOFFLOAD // all features requested
// after: retry with progressively fewer features or log the unwrapped cause
if err := ioctl(uintptr(fd), unix.TUNSETOFFLOAD, uintptr(t.offloadFlags)); err != nil {
t.l.Warn("offload unsupported, continuing without", "err", err)
} Defensive patterns
Strategy: fallback
Validate before calling
// check kernel offload support before enabling vnet hdr
flags := unix.TUN_F_CSUM | unix.TUN_F_TSO4 | unix.TUN_F_TSO6
if err := ioctl(uintptr(fd), unix.TUNSETOFFLOAD, uintptr(flags)); err != nil {
log.Warn("offload unsupported, falling back to no-offload", "err", err)
} Try / catch
if err := startOverlay(); err != nil {
if strings.Contains(err.Error(), "failed to enable offload on multiqueue tun fd") {
// unwrap and retry without offload
log.Warn("retrying without offload", "cause", errors.Unwrap(err))
} else { return err }
} Prevention
- Pin deployments to kernels known to support the requested TUNSETOFFLOAD features
- Test tun startup on your hypervisor/cloud image before rollout
- Log errors.Unwrap(err) to capture the errno for support tickets
When it happens
Trigger: Calling Queues() (which calls addQueue) on a Linux tun with vnetHdr enabled when the kernel rejects the TUNSETOFFLOAD flags — e.g. offloadFlags contains features the kernel/driver doesn't support, the fd is not a valid tun attach fd, or the device was already detached.
Common situations: Running on older kernels or virtualized NICs (some cloud hypervisors) that don't support all requested offload features like TSO/UFO; containers with restricted device access; mismatched nebula build vs kernel capabilities.
Related errors
- failed to set tun device name: %s
- failed to run tun device: %s
- failed to get tun address list: %s
- failed to get tun device link: %s
- failed to bring the tun device up: %s
AI-assisted analysis of slackhq/nebula@dd8f660c0a (2026-09-03).
Data as JSON: /api/errors/a4b73045544c15e3.
Report an issue: GitHub.