slackhq/nebula · error
newTunFromFd not supported in NetBSD
Error message
newTunFromFd not supported in NetBSD
What it means
newTunFromFd on NetBSD is an unimplemented stub that always returns this error. Passing an existing tun fd to the overlay constructor is simply not supported on NetBSD, unlike Linux. The only supported path there is newTun, which opens /dev/tunN by name.
Source
Thrown at overlay/tun_netbsd.go:74
Vltime uint32
Pltime uint32
}
type tun struct {
Device string
vpnNetworks []netip.Prefix
MTU int
Routes atomic.Pointer[[]Route]
routeTree atomic.Pointer[bart.Table[routing.Gateways]]
l *slog.Logger
f *os.File
fd int
}
var deviceNameRE = regexp.MustCompile(`^tun[0-9]+$`)
func newTunFromFd(_ *config.C, _ *slog.Logger, _ int, _ []netip.Prefix) (*tun, error) {
return nil, fmt.Errorf("newTunFromFd not supported in NetBSD")
}
func newTun(c *config.C, l *slog.Logger, vpnNetworks []netip.Prefix, _ bool) (*tun, error) {
// Try to open tun device
var err error
deviceName := c.GetString("tun.dev", "")
if deviceName == "" {
return nil, fmt.Errorf("a device name in the format of /dev/tunN must be specified")
}
if !deviceNameRE.MatchString(deviceName) {
return nil, fmt.Errorf("a device name in the format of /dev/tunN must be specified")
}
fd, err := unix.Open("/dev/"+deviceName, os.O_RDWR, 0)
if err != nil {
return nil, err
}
View on GitHub (pinned to dd8f660c0a)
Solutions
- On NetBSD, configure a device name (tun.dev) so newTun (the /dev/tunN path) is used instead of fd handoff.
- Remove or gate fd-injection logic behind a Linux-only build/runtime check.
- If fd handoff is required, implement newTunFromFd for NetBSD upstream or use an OS with support (Linux).
Example fix
// before: unconditional fd handoff
t, err := overlay.NewTunFromFd(c, l, fd, networks)
// after
if runtime.GOOS == "netbsd" {
t, err = overlay.NewTun(c, l, networks, false)
} else {
t, err = overlay.NewTunFromFd(c, l, fd, networks)
} Defensive patterns
Strategy: fallback
Validate before calling
// choose constructor by platform before calling
if runtime.GOOS == "netbsd" {
// fd path unsupported; must use name-based newTun
return errors.New("fd-based tun creation unsupported on netbsd; set tun.dev")
} Try / catch
t, err := tryNewTunFromFd(c, l, fd, networks)
if err != nil && strings.Contains(err.Error(), "newTunFromFd not supported") {
t, err = newTun(c, l, networks, false) // name-based fallback
} Prevention
- Gate fd-handoff code paths behind runtime.GOOS checks
- Always configure tun.dev so the name-based path works on any OS
- Document OS support matrix for embedding users
When it happens
Trigger: Any call path that constructs the tun from a pre-opened file descriptor while running on NetBSD — e.g. handoff/hot-reload flows or embedders that create the tun device themselves and pass the fd in.
Common situations: Deploying a fd-passing setup (systemd socket handoff, custom embedding, zero-downtime reload) that works on Linux onto a NetBSD host.
Related errors
- newTunFromFd not supported in openbsd
- a device name in the format of /dev/tunN must be specified
- error closing tun file: %w
- failed to get syscall conn for tun: %w
- failed to make read call for tun: %w
AI-assisted analysis of slackhq/nebula@dd8f660c0a (2026-09-03).
Data as JSON: /api/errors/b38ffb95a8771e7d.
Report an issue: GitHub.