{"record":{"id":"7fd22be719fc492d","repo":"netbirdio/netbird","slug":"error-creating-tun-device-s-7fd22b","errorCode":null,"errorMessage":"error creating tun device: %s","messagePattern":"error creating tun device: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"client/iface/device/device_usp_unix.go","lineNumber":51,"sourceCode":"func NewTunDevice(name string, address wgaddr.Address, port int, key string, mtu uint16, iceBind *bind.ICEBind) *TunDevice {\n\tlog.Infof(\"using userspace bind mode\")\n\n\treturn &TunDevice{\n\t\tname:    name,\n\t\taddress: address,\n\t\tport:    port,\n\t\tkey:     key,\n\t\tmtu:     mtu,\n\t\ticeBind: iceBind,\n\t}\n}\n\nfunc (t *TunDevice) Create() (WGConfigurer, error) {\n\tlog.Info(\"create tun interface\")\n\ttunIface, err := tun.CreateTUN(t.name, int(t.mtu))\n\tif err != nil {\n\t\tlog.Debugf(\"failed to create tun interface (%s, %d): %s\", t.name, int(t.mtu), err)\n\t\treturn nil, fmt.Errorf(\"error creating tun device: %s\", err)\n\t}\n\tt.filteredDevice = newDeviceFilter(tunIface)\n\n\t// We need to create a wireguard-go device and listen to configuration requests\n\tt.device = device.NewDevice(\n\t\tt.filteredDevice,\n\t\tt.iceBind,\n\t\tdevice.NewLogger(wgLogLevel(), \"[netbird] \"),\n\t)\n\n\terr = t.assignAddr()\n\tif err != nil {\n\t\tt.device.Close()\n\t\treturn nil, fmt.Errorf(\"error assigning ip: %s\", err)\n\t}\n\n\tt.configurer = configurer.NewUSPConfigurer(t.device, t.name, t.iceBind.ActivityRecorder())\n\terr = t.configurer.ConfigureInterface(t.key, t.port)","sourceCodeStart":33,"sourceCodeEnd":69,"githubUrl":"https://github.com/netbirdio/netbird/blob/93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c/client/iface/device/device_usp_unix.go#L33-L69","documentation":"Userspace-mode Create() on linux/freebsd failed at tun.CreateTUN(name, mtu), which opens /dev/net/tun and performs the TUNSETIFF ioctl with the requested name and MTU. The interface name and MTU are logged at debug level alongside the wrapped cause. The tunnel cannot be created at all when this fires.","triggerScenarios":"/dev/net/tun missing (tun module not loaded or not exposed to the container), EPERM from TUNSETIFF without CAP_NET_ADMIN, EINVAL for a name longer than 15 bytes or already in use with different flags.","commonSituations":"Docker/Podman runs missing --cap-add=NET_ADMIN --device /dev/net/tun; LXC/Proxmox containers without a tun device; hosts where the tun module is not loaded; overlong custom interface names.","solutions":["Run the agent as root or grant CAP_NET_ADMIN","Load the tun module (modprobe tun) and verify /dev/net/tun exists","In containers, start with --device /dev/net/tun --cap-add=NET_ADMIN","Keep the interface name within 15 bytes (IFNAMSIZ-1)"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"if _, err := os.Stat(\"/dev/net/tun\"); err != nil {\n    return fmt.Errorf(\"tun device missing: load the tun module or run the container with --device /dev/net/tun\")\n}\nif os.Geteuid() != 0 {\n    log.Warn(\"tun creation requires root or CAP_NET_ADMIN\")\n}","typeGuard":null,"tryCatchPattern":"if _, err := dev.Create(); err != nil {\n    if strings.Contains(err.Error(), \"error creating tun device\") {\n        // environmental: check /dev/net/tun and privileges, do not retry unchanged\n    }\n    return err\n}","preventionTips":["Pre-flight /dev/net/tun and effective capabilities before bring-up","In containers always pass --cap-add=NET_ADMIN --device /dev/net/tun","Keep interface names within the 15-byte kernel limit"],"tags":["tun","linux","freebsd","userspace","permissions","container"],"backgroundTag":null,"analyzedSha":"93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c","analyzedAt":"2026-08-16T03:09:19.136Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}