prometheus/node_exporter · error
could not get sysfs device info
Error message
could not get sysfs device info: %w
What it means
For attributes the kernel does not expose over netlink (speed, duplex, MTU details, address info), the netclass collector reads per-device files under /sys/class/net/<dev>/. getSysfsAttributes() returns an error if reading/walking those sysfs directories fails, and Update aborts with 'could not get sysfs device info'.
Solutions
- Mount /sys into the container: docker run -v /sys:/sys:ro ... (or equivalent bind mount in Kubernetes hostPath).
- Verify ls /sys/class/net works and files like /sys/class/net/eth0/speed are readable by the exporter user.
- Re-check whether the error is a race with device removal; if so, a node_exporter upgrade may make per-device sysfs failures non-fatal.
- Inspect the wrapped error to see which path/syscall failed; ensure the exporter runs as a user with read access to sysfs.
- Confirm the host, not a Docker-in-Docker inner container, owns the /sys being read.
Example fix
// docker run before (sysfs missing -> collector fails) docker run prom/node-exporter // after docker run -v /proc:/host/proc:ro -v /sys:/host/sys:ro --net=host --privileged prom/node-exporter
Defensive patterns
Strategy: validation
Validate before calling
// preflight: sysfs must expose per-device attribute dirs
if _, err := os.Stat("/sys/class/net"); err != nil {
return fmt.Errorf("sysfs not available: %w", err)
}
entries, _ := os.ReadDir("/sys/class/net")
for _, e := range entries {
if _, err := os.Stat(filepath.Join("/sys/class/net", e.Name(), "speed")); err != nil {
// that device's sysfs attrs will be missing
}
} Try / catch
if err := collector.Update(ch); err != nil {
var perr *fs.PathError
if errors.As(err, &perr) && strings.Contains(err.Error(), "sysfs") {
logger.Warn("sysfs unreadable; check container mounts", "path", perr.Path)
}
} Prevention
- Always bind-mount /sys:ro when running node_exporter in containers
- Pass --path.sysfs matching the mount point
- Run exporter as a user with read access to /sys/class/net/*
- Alert on missing /sys/class/net rather than waiting for scrape errors
When it happens
Trigger: getSysfsAttributes(relevantLinks) returns an error: /sys is not mounted, /sys/class/net/<iface> entries are unreadable (permissions), or an I/O error occurs while reading device attribute files (e.g. device hot-unplugged mid-scan).
Common situations: Containers launched without /sys mounted read-write or read-only (common in minimal Docker configs missing --volume /sys:/sys:ro); host /sys hidden by LSM policies; NICs removed between the rtnetlink dump and the sysfs read (race in virtualized environments).
Understand the failure class
Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.
Related errors
- Could not derive a human-readable chip type for
- failed to open sysfs
- failed to retrieve bcache stats
- failed to open sysfs
- failed to retrieve bcachefs stats
AI-assisted analysis of prometheus/node_exporter@17ddd77c59 (2026-09-07).
Data as JSON: /api/errors/642d22236d89f064.
Report an issue: GitHub.
Appendix: source
Thrown at collector/netclass_rtnl_linux.go:77
}
// Get most attributes from Netlink
lMsgs, err := c.getNetClassInfoRTNL()
if err != nil {
return fmt.Errorf("could not get net class info: %w", err)
}
relevantLinks := make([]rtnetlink.LinkMessage, 0, len(lMsgs))
for _, msg := range lMsgs {
if !c.ignoredDevicesPattern.MatchString(msg.Attributes.Name) {
relevantLinks = append(relevantLinks, msg)
}
}
// Read sysfs for attributes that Netlink doesn't expose
sysfsAttrs, err := getSysfsAttributes(relevantLinks)
if err != nil {
return fmt.Errorf("could not get sysfs device info: %w", err)
}
// Parse all the info and update metrics
for _, msg := range relevantLinks {
upDesc := prometheus.NewDesc(
prometheus.BuildFQName(namespace, c.subsystem, "up"),
"Value is 1 if operstate is 'up', 0 otherwise.",
[]string{"device"},
nil,
)
upValue := 0.0
if msg.Attributes.OperationalState == rtnetlink.OperStateUp {
upValue = 1.0
}
ch <- prometheus.MustNewConstMetric(upDesc, prometheus.GaugeValue, upValue, msg.Attributes.Name)
infoDesc := prometheus.NewDesc(
prometheus.BuildFQName(namespace, c.subsystem, "info"),View on GitHub (pinned to 17ddd77c59)