{"record":{"id":"25925d782896a7c2","repo":"slackhq/nebula","slug":"newtun-not-supported-in-android","errorCode":null,"errorMessage":"newTun not supported in Android","messagePattern":"newTun not supported in Android","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"overlay/tun_android.go","lineNumber":59,"sourceCode":"\n\terr := t.reload(c, true)\n\tif err != nil {\n\t\t_ = file.Close()\n\t\treturn nil, err\n\t}\n\n\tc.RegisterReloadCallback(func(c *config.C) {\n\t\terr := t.reload(c, false)\n\t\tif err != nil {\n\t\t\tutil.LogWithContextIfNeeded(\"failed to reload tun device\", err, t.l)\n\t\t}\n\t})\n\n\treturn t, nil\n}\n\nfunc newTun(_ *config.C, _ *slog.Logger, _ []netip.Prefix, _ bool) (*tun, error) {\n\treturn nil, fmt.Errorf(\"newTun not supported in Android\")\n}\n\nfunc (t *tun) RoutesFor(ip netip.Addr) routing.Gateways {\n\tr, _ := t.routeTree.Load().Lookup(ip)\n\treturn r\n}\n\nfunc (t *tun) Activate() error {\n\treturn nil\n}\n\nfunc (t *tun) reload(c *config.C, initial bool) error {\n\tchange, routes, err := getAllRoutesFromConfig(c, t.vpnNetworks, initial)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif !initial && !change {","sourceCodeStart":41,"sourceCodeEnd":77,"githubUrl":"https://github.com/slackhq/nebula/blob/dd8f660c0ac37903ec4080ca4d3c861ba9342ceb/overlay/tun_android.go#L41-L77","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\ntunDev, err := tun.New(c, l, vpnNetworks, false)\n// after\nfd, err := androidVpnServiceEstablish() // int fd from VpnService.Builder.establish()\ntunDev, err := tun.NewFromFd(c, l, fd, vpnNetworks)","handlingStrategy":"fallback","validationCode":"if runtime.GOOS == \"android\" {\n    // never call tun.New(); obtain fd from VpnService first\n    fd := getAndroidVpnFd()\n    return tun.NewFromFd(c, l, fd, vpnNetworks)\n}","typeGuard":null,"tryCatchPattern":"t, err := tun.New(c, l, vpnNetworks, false)\nif err != nil && strings.Contains(err.Error(), \"not supported in Android\") {\n    // switch to fd-based TUN via VpnService.Builder.establish()\n}","preventionTips":["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"],"tags":["android","tun-device","unsupported-platform"],"backgroundTag":"tun-device-unsupported-platform","analyzedSha":"dd8f660c0ac37903ec4080ca4d3c861ba9342ceb","analyzedAt":"2026-09-03T11:13:55.444Z","contentChangedAt":"2026-09-03T11:13:55.444Z","schemaVersion":2},"datasetVersion":"2026-09-10T17:17:09.494Z"}