{"record":{"id":"f6f3d9367d68b9f9","repo":"slackhq/nebula","slug":"newtunfromfd-not-supported","errorCode":null,"errorMessage":"newTunFromFd not supported","messagePattern":"newTunFromFd not supported","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"overlay/tun_tester.go","lineNumber":56,"sourceCode":"\t}\n\trouteTree, err := makeRouteTree(l, routes, false)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &TestTun{\n\t\tDevice:      c.GetString(\"tun.dev\", \"\"),\n\t\tvpnNetworks: vpnNetworks,\n\t\tRoutes:      routes,\n\t\trouteTree:   routeTree,\n\t\tl:           l,\n\t\trxPackets:   make(chan []byte, 10),\n\t\tTxPackets:   make(chan []byte, 10),\n\t}, nil\n}\n\nfunc newTunFromFd(_ *config.C, _ *slog.Logger, _ int, _ []netip.Prefix) (*TestTun, error) {\n\treturn nil, fmt.Errorf(\"newTunFromFd not supported\")\n}\n\n// Send will place a byte array onto the receive queue for nebula to consume.\n// These are unencrypted ip layer frames destined for another nebula node.\n// packets should exit the udp side, capture them with udpConn.Get.\n//\n// Send copies the input via the freelist, so the caller is free to mutate\n// or reuse it after the call returns.\nfunc (t *TestTun) Send(packet []byte) {\n\tif t.closed.Load() {\n\t\treturn\n\t}\n\n\tif t.l.Enabled(context.Background(), slog.LevelDebug) {\n\t\tt.l.Debug(\"Tun receiving injected packet\", \"dataLen\", len(packet))\n\t}\n\tbuf := acquireTunBuf(len(packet))\n\tcopy(buf, packet)","sourceCodeStart":38,"sourceCodeEnd":74,"githubUrl":"https://github.com/slackhq/nebula/blob/dd8f660c0ac37903ec4080ca4d3c861ba9342ceb/overlay/tun_tester.go#L38-L74","documentation":"newTunFromFd in overlay/tun_tester.go is a stub: the tester TUN implementation only supports creating a device from config, not from a file descriptor. Calling it always returns 'newTunFromFd not supported'. It exists so the test harness satisfies the Device constructor interface.","triggerScenarios":"Invoking newTunFromFd with a *config.C, logger, fd int and prefixes while running against the TestTun/tester overlay — i.e. code paths that use tun.fd on the test build.","commonSituations":"Running nebula in test mode with a config that specifies tun.fd or handoff of a pre-opened tunnel fd; custom integration harnesses that assume fd-based TUN injection works under the tester.","solutions":["Don't pass a pre-opened fd when using the tester overlay; remove tun.fd from the config so newTun is used instead.","Use the real OS overlay (linux/bsd) if you need fd-based TUN handoff.","If you need this in tests, implement fd support in TestTun or mock the constructor in your harness."],"exampleFix":"// before\nc:\n  tun:\n    fd: 3\n// after\nc:\n  tun:\n    dev: tun0   # let the tester/OS create the device instead of handing in an fd","handlingStrategy":"fallback","validationCode":"if fd, ok := c.GetInt(\"tun.fd\"); ok && fd > 0 {\n\treturn errors.New(\"tester overlay does not support tun.fd; remove it from config\")\n}","typeGuard":null,"tryCatchPattern":"tun, err := overlay.NewTunFromFd(cfg, logger, fd, prefixes)\nif err != nil && strings.Contains(err.Error(), \"not supported\") {\n\ttun, err = overlay.NewTun(cfg, logger, prefixes, false) // fallback to normal creation\n}","preventionTips":["Never set tun.fd when running the tester overlay.","Use fd-based TUN only with real OS overlays.","Mock Device construction in test harnesses rather than using fd paths."],"tags":["testing","tun","unsupported-feature"],"backgroundTag":"unsupported-operation","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"}