slackhq/nebula · critical
failed to set tun device head: %w
Error message
failed to set tun device head: %w
What it means
This error is returned by the NetBSD TUN device's Activate method when the TUNSIFHEAD ioctl fails. TUNSIFHEAD enables the 4-byte address-family header on packets read/written to the tun device, which is required to carry both IPv4 and IPv6 over the same tunnel. If the kernel rejects the ioctl, the device cannot be used for dual-stack VPN traffic, so activation aborts.
Source
Thrown at overlay/tun_netbsd.go:313
return fmt.Errorf("failed to set tun address %s: %s", cidr.Addr().String(), err)
}
return nil
}
return fmt.Errorf("unknown address type %v", cidr)
}
func (t *tun) Activate() error {
mode := int32(unix.IFF_BROADCAST)
err := ioctl(uintptr(t.fd), TUNSIFMODE, uintptr(unsafe.Pointer(&mode)))
if err != nil {
return fmt.Errorf("failed to set tun device mode: %w", err)
}
v := 1
err = ioctl(uintptr(t.fd), TUNSIFHEAD, uintptr(unsafe.Pointer(&v)))
if err != nil {
return fmt.Errorf("failed to set tun device head: %w", err)
}
err = t.doIoctlByName(unix.SIOCSIFMTU, uint32(t.MTU))
if err != nil {
return fmt.Errorf("failed to set tun mtu: %w", err)
}
for i := range t.vpnNetworks {
err = t.addIp(t.vpnNetworks[i])
if err != nil {
return err
}
}
return t.addRoutes(false)
}
func (t *tun) doIoctlByName(ctl uintptr, value uint32) error {View on GitHub (pinned to dd8f660c0a)
Solutions
- Verify the process runs as root or with the privileges needed to configure network interfaces.
- Confirm the fd passed to newTun is a valid NetBSD tun device (/dev/tunN) and the tun kernel module is loaded (modload if_tun).
- Check the wrapped errno (%w) with errors.Is to identify whether it is EBADF/ENOTTY/EPERM and fix accordingly.
- Rebuild/reboot the kernel with tun(4) support if the ioctl returns ENOTTY or ENODEV.
Defensive patterns
Strategy: try-catch
Validate before calling
// Before Activate: ensure we are root and the tun driver is present
if os.Geteuid() != 0 {
return fmt.Errorf("activating tun device requires root privileges")
}
if _, err := os.Stat("/dev/tun"); err != nil {
return fmt.Errorf("tun device not available: %w", err)
} Try / catch
if err := t.Activate(); err != nil {
var syscallErr syscall.Errno
if errors.As(err, &syscallErr) {
switch syscallErr {
case unix.EPERM, unix.EACCES:
// missing privileges
case unix.ENOTTY, unix.ENODEV:
// fd is not a tun device / driver missing
}
}
return fmt.Errorf("tun activation failed: %w", err)
} Prevention
- Run the VPN process as root or with equivalent interface-configuration privileges.
- Confirm the NetBSD kernel has tun(4) support (modload if_tun) before starting.
- Check errors.Is/errors.As on the wrapped errno to diagnose ioctl failures precisely.
- Open the tun device through the library's newTun path rather than passing arbitrary fds.
When it happens
Trigger: Calling Activate() on a NetBSD tun where the ioctl(fd, TUNSIFHEAD, &1) call fails — e.g. the file descriptor is not a tun device, the tun driver is not loaded, or the fd lacks sufficient permissions.
Common situations: Running the VPN binary on a NetBSD host where /dev/tun was not opened correctly, the kernel lacks the tun(4) driver, or the process runs without root privileges to configure the interface.
Related errors
- failed to enable offload on multiqueue tun fd: %w
- failed to set tun device name: %s
- failed to run tun device: %s
- failed to set tun address %s: %s
- failed to set tun device mode: %w
AI-assisted analysis of slackhq/nebula@dd8f660c0a (2026-09-03).
Data as JSON: /api/errors/5ff39462e57e0d53.
Report an issue: GitHub.