cilium/cilium · error
retrieving device %s: %w
Error message
retrieving device %s: %w
What it means
DeviceHasSKBProgramLoaded looks up the given network device to inspect whether a Cilium BPF program is attached; the safenetlink.LinkByName lookup itself failed, so attachment state could not be determined. This wraps the underlying netlink error (typically ENODEV).
Source
Thrown at pkg/datapath/loader/netlink.go:532
return nil
}
if err := netlink.LinkSetName(link, to); err != nil {
return fmt.Errorf("renaming device %s to %s: %w", from, to, err)
}
return nil
}
// DeviceHasSKBProgramLoaded returns true if the given device has a tc(x) program
// attached.
//
// If checkEgress is true, returns true if there's both an ingress and
// egress program attached.
func DeviceHasSKBProgramLoaded(device string, checkEgress bool) (bool, error) {
link, err := safenetlink.LinkByName(device)
if err != nil {
return false, fmt.Errorf("retrieving device %s: %w", device, err)
}
itcx, err := hasCiliumTCXLinks(link, ebpf.AttachTCXIngress)
if err != nil {
return false, fmt.Errorf("failed to check for cilium tcx links on ingress: %w", err)
}
itc, err := hasCiliumTCFilters(link, netlink.HANDLE_MIN_INGRESS)
if err != nil {
return false, fmt.Errorf("failed to check for cilium tc filters on ingress: %w", err)
}
ink, err := hasCiliumNetkitLinks(link, ebpf.AttachNetkitPeer)
if err != nil {
return false, fmt.Errorf("failed to check for cilium netkit links: %w", err)
}
// Need ingress programs at minimum, bail out if these are already missing.
if !itc && !itcx && !ink {
return false, nilView on GitHub (pinned to ac7b90affa)
Solutions
- Verify the device exists: ip link show <device> in the same netns the agent runs in.
- Update the devices list in the CiliumConfig to match current interface names (device renames after reboot are common).
- If running from a test/tool, execute in the host network namespace (nsenter -t 1 -n) rather than a container netns.
- Re-run the check after the agent re-syncs its device list; transient ENODEV during pod teardown usually self-heals.
Example fix
// before
loaded, err := DeviceHasSKBProgramLoaded("eno1", true)
// after: guard the lookup
if _, err := net.InterfaceByName("eno1"); err != nil {
return fmt.Errorf("device eno1 not present: %w", err)
}
loaded, err := DeviceHasSKBProgramLoaded("eno1", true) Defensive patterns
Strategy: validation
Validate before calling
if _, err := net.InterfaceByName(device); err != nil {
return fmt.Errorf("device %q not present in this netns: %w", device, err)
}
loaded, err := loader.DeviceHasSKBProgramLoaded(device, true) Type guard
func deviceExists(name string) bool {
_, err := net.InterfaceByName(name)
return err == nil
} Try / catch
loaded, err := loader.DeviceHasSKBProgramLoaded("eth0", true)
if err != nil {
var eno unix.Errno
if errors.As(err, &eno) && eno == unix.ENODEV {
log.Printf("device missing; re-syncing Cilium device config")
}
return err
} Prevention
- Keep the devices list in CiliumConfig in sync with actual interface names, especially after reboots/renames.
- Run inspection tools in the host network namespace (nsenter -t 1 -n).
- Check `ip link show <device>` before invoking datapath inspection APIs.
- Use stable interface names (netplan/ifcfg) to avoid predictable-naming drift.
When it happens
Trigger: Calling DeviceHasSKBProgramLoaded with a device name that does not exist in the current network namespace, a misspelled interface name, or when the device was removed after configuration was generated (device list out of sync).
Common situations: CiliumConfig devices changed (e.g. enp5s0 renamed to eth0 after reboot or by predictable-naming), datapath reload running in the wrong netns (e.g. inside a container instead of host), or veth devices torn down by pod deletion.
Related errors
- error getting IPsec decryption interfaces: %w
- failed to list interfaces: %w
- collecting device program stats for endpoint %d interface %s
- collecting device program stats for interface %s: %w
- getting link by name for %s: %w
AI-assisted analysis of cilium/cilium@ac7b90affa (2026-08-31).
Data as JSON: /api/errors/f3722a9ae5a3fd70.
Report an issue: GitHub.