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
- Obtain a TUN file descriptor from Android VpnService.Builder.establish() and pass it to newTunFromFd instead of newTun.
- Run nebula inside the official Android app (MobileNebula) which wires up the fd-based TUN for you.
- 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
- On Android always establish the VPN fd and use NewFromFd
- Never run the plain nebula binary as the TUN owner on Android
- Gate TUN creation code with runtime.GOOS checks in embedded builds
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
- newTunFromFd not supported in Darwin
- failed to initialize interface: %s
- failed to run tun device: %s
- unable to determine IP version from packet
- newTunFromFd not supported in FreeBSD
AI-assisted analysis of slackhq/nebula@dd8f660c0a (2026-09-03).
Data as JSON: /api/errors/25925d782896a7c2.
Report an issue: GitHub.