{"record":{"id":"70e76c243d40b754","repo":"slackhq/nebula","slug":"a-device-name-in-the-format-of-dev-tunn-must-be-s-70e76c","errorCode":null,"errorMessage":"a device name in the format of /dev/tunN must be specified","messagePattern":"a device name in the format of /dev/tunN must be specified","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"overlay/tun_openbsd.go","lineNumber":73,"sourceCode":"\tRoutes      atomic.Pointer[[]Route]\n\trouteTree   atomic.Pointer[bart.Table[routing.Gateways]]\n\tl           *slog.Logger\n\tf           *os.File\n\tfd          int\n}\n\nvar deviceNameRE = regexp.MustCompile(`^tun[0-9]+$`)\n\nfunc newTunFromFd(_ *config.C, _ *slog.Logger, _ int, _ []netip.Prefix) (*tun, error) {\n\treturn nil, fmt.Errorf(\"newTunFromFd not supported in openbsd\")\n}\n\nfunc newTun(c *config.C, l *slog.Logger, vpnNetworks []netip.Prefix, _ bool) (*tun, error) {\n\t// Try to open tun device\n\tvar err error\n\tdeviceName := c.GetString(\"tun.dev\", \"\")\n\tif deviceName == \"\" {\n\t\treturn nil, fmt.Errorf(\"a device name in the format of /dev/tunN must be specified\")\n\t}\n\tif !deviceNameRE.MatchString(deviceName) {\n\t\treturn nil, fmt.Errorf(\"a device name in the format of /dev/tunN must be specified\")\n\t}\n\n\tfd, err := unix.Open(\"/dev/\"+deviceName, os.O_RDWR, 0)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\terr = unix.SetNonblock(fd, true)\n\tif err != nil {\n\t\tl.Warn(\"Failed to set the tun device as nonblocking\", \"error\", err)\n\t}\n\n\tt := &tun{\n\t\tf:           os.NewFile(uintptr(fd), \"\"),\n\t\tfd:          fd,","sourceCodeStart":55,"sourceCodeEnd":91,"githubUrl":"https://github.com/slackhq/nebula/blob/dd8f660c0ac37903ec4080ca4d3c861ba9342ceb/overlay/tun_openbsd.go#L55-L91","documentation":"newTun on OpenBSD requires an explicit tun device name via the 'tun.dev' config key. If the value is empty, the constructor refuses to proceed because OpenBSD tun devices must be opened by path (/dev/tunN), unlike Linux which can clone /dev/net/tun. This error signals the mandatory config key is missing.","triggerScenarios":"Starting nebula with tun.enabled and no 'tun.dev' set in the config file (c.GetString(\"tun.dev\", \"\") returns \"\").","commonSituations":"Copying a Linux-oriented config to an OpenBSD host; forgetting platform-specific tun settings; generating configs from templates that omit tun.dev.","solutions":["Set 'tun.dev: /dev/tun0' (or the appropriate /dev/tunN) in the config file","Verify with `ls /dev/tun*` which tun devices exist and pick a free one","Create the device if missing: `cd /dev && sh MAKEDEV tun0`"],"exampleFix":"# before\ntun:\n  enabled: true\n# after\ntun:\n  enabled: true\n  dev: /dev/tun0","handlingStrategy":"validation","validationCode":"dev := cfg.GetString(\"tun.dev\", \"\")\nif dev == \"\" {\n    return fmt.Errorf(\"tun.dev must be set on OpenBSD, e.g. /dev/tun0\")\n}\nif _, err := os.Stat(\"/dev/\" + strings.TrimPrefix(dev, \"/dev/\")); err != nil {\n    return fmt.Errorf(\"tun device %s not found\", dev)\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always set tun.dev in OpenBSD configs","Check for /dev/tun* device nodes at startup","Document platform-specific tun keys in config templates"],"tags":["openbsd","tun","config","missing-config"],"backgroundTag":"missing-tun-device","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"}