slackhq/nebula · error

newTun not supported in Android

Error message

newTun not supported in Android

What it means

On Android, nebula's overlay/TUN device is not created in-process. The Android app supplies an existing file descriptor from VpnService.Builder.establish(), so newTun() is a stub that always returns this error. Any code path that tries to create a TUN from config on Android will fail with this message.

Source

Thrown at overlay/tun_android.go:59

	err := t.reload(c, true)
	if err != nil {
		_ = file.Close()
		return nil, err
	}

	c.RegisterReloadCallback(func(c *config.C) {
		err := t.reload(c, false)
		if err != nil {
			util.LogWithContextIfNeeded("failed to reload tun device", err, t.l)
		}
	})

	return t, nil
}

func newTun(_ *config.C, _ *slog.Logger, _ []netip.Prefix, _ bool) (*tun, error) {
	return nil, fmt.Errorf("newTun not supported in Android")
}

func (t *tun) RoutesFor(ip netip.Addr) routing.Gateways {
	r, _ := t.routeTree.Load().Lookup(ip)
	return r
}

func (t *tun) Activate() error {
	return nil
}

func (t *tun) reload(c *config.C, initial bool) error {
	change, routes, err := getAllRoutesFromConfig(c, t.vpnNetworks, initial)
	if err != nil {
		return err
	}

	if !initial && !change {

View on GitHub (pinned to dd8f660c0a)

Solutions

  1. Obtain a TUN file descriptor from Android VpnService.Builder.establish() and pass it to newTunFromFd instead of newTun.
  2. Run nebula inside the official Android app (MobileNebula) which wires up the fd-based TUN for you.
  3. If testing on Android is not the goal, build/run for linux (GOOS=linux) where newTun is implemented.

Example fix

// before
tunDev, err := tun.New(c, l, vpnNetworks, false)
// after
fd, err := androidVpnServiceEstablish() // int fd from VpnService.Builder.establish()
tunDev, err := tun.NewFromFd(c, l, fd, vpnNetworks)
Defensive patterns

Strategy: fallback

Validate before calling

if runtime.GOOS == "android" {
    // never call tun.New(); obtain fd from VpnService first
    fd := getAndroidVpnFd()
    return tun.NewFromFd(c, l, fd, vpnNetworks)
}

Try / catch

t, err := tun.New(c, l, vpnNetworks, false)
if err != nil && strings.Contains(err.Error(), "not supported in Android") {
    // switch to fd-based TUN via VpnService.Builder.establish()
}

Prevention

When it happens

Trigger: Calling the TUN creation path (newTun) on a build with the Android build tag, e.g. running nebula as a plain binary on Android instead of embedding it behind the Android VPN service.

Common situations: Running the nebula binary directly on Android instead of inside the official Android app wrapper; building for android OS without using tun.newTunFromFd; CI tests executing newTun on an android-tagged build.

Related errors


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