{"record":{"id":"435093165d1e6ee7","repo":"prometheus/node_exporter","slug":"could-not-get-link-modes-w","errorCode":null,"errorMessage":"could not get link modes: %w","messagePattern":"could not get link modes: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"collector/netclass_rtnl_linux.go","lineNumber":45,"sourceCode":"\t\"github.com/mdlayher/ethtool\"\n\t\"github.com/prometheus/client_golang/prometheus\"\n\t\"github.com/prometheus/procfs/sysfs\"\n)\n\nvar (\n\tnetclassRTNLWithStats = kingpin.Flag(\"collector.netclass_rtnl.with-stats\", \"Expose the statistics for each network device, replacing netdev collector.\").Bool()\n\toperstateStr          = []string{\n\t\t\"unknown\", \"notpresent\", \"down\", \"lowerlayerdown\", \"testing\",\n\t\t\"dormant\", \"up\",\n\t}\n)\n\nfunc (c *netClassCollector) netClassRTNLUpdate(ch chan<- prometheus.Metric) error {\n\tlinkModes := make(map[string]*ethtool.LinkMode)\n\tlms, err := c.getLinkModes()\n\tif err != nil {\n\t\tif !errors.Is(errors.Unwrap(err), fs.ErrNotExist) {\n\t\t\treturn fmt.Errorf(\"could not get link modes: %w\", err)\n\t\t}\n\t\tc.logger.Info(\"ETHTOOL netlink interface unavailable, duplex and linkspeed are not scraped.\")\n\t} else {\n\t\tfor _, lm := range lms {\n\t\t\tif c.ignoredDevicesPattern.MatchString(lm.Interface.Name) {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif lm.SpeedMegabits >= 0 {\n\t\t\t\tspeedBytes := uint64(lm.SpeedMegabits * 1000 * 1000 / 8)\n\t\t\t\tpushMetric(ch, c.getFieldDesc(\"speed_bytes\"), speedBytes, prometheus.GaugeValue, lm.Interface.Name)\n\t\t\t}\n\t\t\tlinkModes[lm.Interface.Name] = lm\n\t\t}\n\t}\n\n\t// Get most attributes from Netlink\n\tlMsgs, err := c.getNetClassInfoRTNL()\n\tif err != nil {","sourceCodeStart":27,"sourceCodeEnd":63,"githubUrl":"https://github.com/prometheus/node_exporter/blob/17ddd77c59ba27e1508e9f7894b1e55b44d6aed3/collector/netclass_rtnl_linux.go#L27-L63","documentation":"node_exporter's netclass collector wraps any failure from getLinkModes(), which queries the ETHTOOL netlink socket to learn duplex and link-speed per interface. If the error is not fs.ErrNotExist (i.e. it is not simply 'the netlink interface is unavailable'), the collector aborts its whole Update with this wrapped error. It exists so duplex/linkspeed data loss is distinguishable from total netclass failure.","triggerScenarios":"getLinkModes() returns a non-ErrNotExist error: the ethtool netlink socket cannot be created/opened, the netlink query to the kernel fails (e.g. socket permission issue, kernel without CONFIG_ETHTOOL_NETLINK support returning an unexpected error rather than a missing file), or a syscall error while dumping link modes.","commonSituations":"Running on kernels older than 5.6 where ETHTOOL netlink genetlink family is absent but the ethtool library surfaces the absence as something other than fs.ErrNotExist; running in restricted containers/seccomp environments that block NETLINK_GENERIC socket creation; older node_exporter/ethtool-go library versions whose error wrapping no longer matches errors.Unwrap(err)==fs.ErrNotExist so the graceful-degradation path is missed.","solutions":["Upgrade node_exporter (and its ethtool dependency) so the missing-ETHTOOL-netlink case is detected via errors.Is(err, fs.ErrNotExist) and degrades gracefully to Info log.","Verify the kernel supports CONFIG_ETHTOOL_NETLINK (kernel >= 5.6) with `ls /sys/kernel/debug` or check `genl ctrl list | grep -i ethtool`.","Check container seccomp/AppArmor policies allow socket(AF_NETLINK) with NETLINK_GENERIC.","If duplex/linkspeed are not needed, the error itself does not block other netclass metrics only in newer versions — otherwise run with --collector.netclass and confirm which sub-metrics fail; file an issue if the error surfaces on a supported kernel.","Reproduce with strace -f -e trace=socket,sendto,recvfrom to see whether the netlink socket creation or the dump fails."],"exampleFix":"// before (older detection logic that misses the degraded case)\nif err != nil {\n    return fmt.Errorf(\"could not get link modes: %w\", err)\n}\n// after (graceful degradation when ethtool netlink is unavailable)\nif err != nil {\n    if !errors.Is(errors.Unwrap(err), fs.ErrNotExist) {\n        return fmt.Errorf(\"could not get link modes: %w\", err)\n    }\n    c.logger.Info(\"ETHTOOL netlink interface unavailable, duplex and linkspeed are not scraped.\")\n}","handlingStrategy":"fallback","validationCode":"// check ETHTOOL netlink family availability before scraping\ngenl, err := genetlink.Dial(nil)\nif err != nil { /* log: ethtool netlink unavailable */ }\nelse if _, err := genl.GetFamily(\"ethtool\"); err != nil {\n    // fall back: duplex/linkspeed will not be scraped\n}","typeGuard":"func isEthtoolUnavailable(err error) bool {\n\treturn errors.Is(errors.Unwrap(err), fs.ErrNotExist)\n}","tryCatchPattern":"if err := collector.Update(ch); err != nil {\n\tvar wrapped *fmt.wrapError\n\tif errors.As(err, &wrapped) && strings.Contains(err.Error(), \"could not get link modes\") {\n\t\tlogger.Info(\"ethtool netlink unavailable; continuing without duplex/linkspeed\")\n\t} else {\n\t\treturn err\n\t}\n}","preventionTips":["Pin kernel >= 5.6 where CONFIG_ETHTOOL_NETLINK exists","Keep node_exporter current so missing-ethtool degrades to an Info log","Ensure container seccomp profiles allow AF_NETLINK sockets","Alert on the log line 'ETHTOOL netlink interface unavailable' rather than paging on it"],"tags":["linux","netlink","ethtool","network"],"backgroundTag":"network-request-failed","analyzedSha":"17ddd77c59ba27e1508e9f7894b1e55b44d6aed3","analyzedAt":"2026-09-07T17:54:06.211Z","contentChangedAt":"2026-09-07T17:54:06.211Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}