XTLS/Xray-core · error
invalid xray.tun.fd: TUN device name {actualName} does not m
Error message
invalid xray.tun.fd: TUN device name {actualName} does not match configured name {expectedName} What it means
When a TUN device name is configured, Xray compares it against the actual name reported by TUNGETIFF (ifr.Name()). A mismatch means the fd belongs to a different TUN interface than the one named in the inbound config, which would make the subsequent netlink configuration (addresses, routes) target the wrong device.
Source
Thrown at proxy/tun/tun_linux.go:105
ifr, err := unix.NewIfreq("")
if err != nil {
return -1, nil, true, err
}
if err = unix.IoctlIfreq(fd, unix.TUNGETIFF, ifr); err != nil {
return -1, nil, true, err
}
flags := ifr.Uint16()
if flags&unix.IFF_TUN == 0 {
return -1, nil, true, errors.New("invalid ", platform.TunFdKey, ": file descriptor is not a TUN device")
}
if flags&unix.IFF_NO_PI == 0 {
return -1, nil, true, errors.New("invalid ", platform.TunFdKey, ": TUN device must use IFF_NO_PI")
}
actualName := ifr.Name()
if expectedName != "" && actualName != expectedName {
return -1, nil, true, errors.New("invalid ", platform.TunFdKey, ": TUN device name ", actualName, " does not match configured name ", expectedName)
}
tunLink, err := netlink.LinkByName(actualName)
if err != nil {
return -1, nil, true, err
}
if err = unix.SetNonblock(fd, true); err != nil {
return -1, nil, true, err
}
return fd, tunLink, true, nil
}
// open the file that implements tun interface in the OS
func open(name string) (int, error) {
fd, err := unix.Open("/dev/net/tun", unix.O_RDWR, 0)
if err != nil {View on GitHub (pinned to 7d214f8b09)
Solutions
- Align the configured TUN name with the actual interface name (check `ip link` / TUNGETIFF result)
- Pin the name when creating the device externally so it is deterministic (TUNSETIFF with the exact name)
- Omit the expected name in config if the actual name is not known ahead of time
Example fix
// before: config names tun0, fd is tun1
{ "name": "tun0", ... } // fd actually belongs to tun1
// after
ip tuntap add mode tun name tun0 # create with fixed name, pass its fd
{ "name": "tun0", ... } Defensive patterns
Strategy: validation
Validate before calling
// before handing over the fd, read its real name and reconcile with config
ifr, _ := unix.NewIfreq("")
_ = unix.IoctlIfreq(fd, unix.TUNGETIFF, ifr)
actual := ifr.Name()
if cfgName != "" && cfgName != actual {
log.Fatalf("config name %q != actual tun name %q", cfgName, actual)
} Prevention
- Create persistent TUN devices with fixed names (ip tuntap add name X)
- Derive the configured name from TUNGETIFF instead of hardcoding
- Leave the name unset when the environment assigns names dynamically
When it happens
Trigger: Configuring name "tun0" in the tun inbound while xray.tun.fd refers to tun1; a TUN manager that renames or numbers devices dynamically; reusing a config after the OS assigned a different free tunN name.
Common situations: Persisted configs paired with an external fd provider that opens whichever tunN is free; Android VpnService where the interface name is chosen by the framework; typo in the configured name.
Related errors
- invalid xray.tun.fd: file descriptor is not a TUN device
- invalid xray.tun.fd: TUN device must use IFF_NO_PI
- invalid interface address {address}
- invalid system route {cidr}
- outbound interface cannot be the TUN interface
AI-assisted analysis of XTLS/Xray-core@7d214f8b09 (2026-08-15).
Data as JSON: /api/errors/a9f2f8fbcec41720.
Report an issue: GitHub.