slackhq/nebula · critical

can not load the wintun driver: %w

Error message

can not load the wintun driver: %w

What it means

newTun on Windows requires the wintun.dll driver. checkWinTunExists() tries to load wintun.dll; when that fails, nebula wraps the cause as 'can not load the wintun driver'. Without wintun.dll the TUN device cannot be created and nebula cannot start.

Source

Thrown at overlay/tun_windows.go:61

	bypassWDF       bool
	wdfBypass       closer
	l               *slog.Logger

	tun *wintun.NativeTun
}

func (t *winTun) Read(b []byte) (int, error) {
	return t.tun.Read(b, 0)
}

func newTunFromFd(_ *config.C, _ *slog.Logger, _ int, _ []netip.Prefix) (Device, error) {
	return nil, fmt.Errorf("newTunFromFd not supported in Windows")
}

func newTun(c *config.C, l *slog.Logger, vpnNetworks []netip.Prefix, _ bool) (*winTun, error) {
	err := checkWinTunExists()
	if err != nil {
		return nil, fmt.Errorf("can not load the wintun driver: %w", err)
	}

	deviceName := c.GetString("tun.dev", "")
	guid, err := generateGUIDByDeviceName(deviceName)
	if err != nil {
		return nil, fmt.Errorf("generate GUID failed: %w", err)
	}

	cat, setCat, err := parseNetworkCategory(c.GetString("tun.network_category", "private"))
	if err != nil {
		return nil, err
	}

	t := &winTun{
		Device:          deviceName,
		vpnNetworks:     vpnNetworks,
		MTU:             c.GetInt("tun.mtu", DefaultMTU),
		guid:            *guid,

View on GitHub (pinned to dd8f660c0a)

Solutions

  1. Download the official wintun distribution and place the architecture-correct wintun.dll next to nebula.exe (or in PATH).
  2. Verify DLL architecture matches the nebula binary (x64/x86/arm64).
  3. Check antivirus/EDR quarantine logs and whitelist wintun.dll.
  4. Ensure the wintun.dll version is one supported by your nebula release and not corrupted (re-download and compare checksums).

Example fix

// before
nebula.exe in C:\nebula\ with no wintun.dll anywhere on PATH
// after
C:\nebula\
  nebula.exe
  wintun.dll   (amd64 build matching the nebula binary)
Defensive patterns

Strategy: validation

Validate before calling

if _, err := os.Stat(filepath.Join(exeDir, "wintun.dll")); err != nil {
	return errors.New("wintun.dll missing next to nebula.exe; install the official wintun distribution")
}

Try / catch

tun, err := overlay.NewTun(cfg, logger, prefixes, false)
if err != nil && strings.Contains(err.Error(), "wintun driver") {
	// surface install guidance: correct-arch wintun.dll beside the binary
	return fmt.Errorf("install wintun: %w", err)
}

Prevention

When it happens

Trigger: newTun calls checkWinTunExists() and LoadLibrary/finds no wintun.dll on the search path, an architecture-mismatched DLL (e.g. 32-bit DLL with 64-bit nebula), or a corrupted/incompatible wintun version.

Common situations: wintun.dll missing next to nebula.exe or in PATH; wrong architecture (x86 vs x64 vs arm64) DLL; antivirus quarantining wintun.dll; running from a stripped-down environment where the DLL wasn't bundled.

Related errors


AI-assisted analysis of slackhq/nebula@dd8f660c0a (2026-09-03). Data as JSON: /api/errors/0ad4a5c6b722218f. Report an issue: GitHub.