prometheus/node_exporter · error
couldn't get netdev labels
Error message
couldn't get netdev labels: %w
What it means
After netdev stats are fetched, Update calls getNetDevLabels() to build the per-device label set (e.g. device speed/duplex annotations read from sysfs). A failure there is wrapped as 'couldn't get netdev labels' and the netdev scrape fails even though the raw stats were already collected successfully.
Solutions
- Mount sysfs read-only into the container: -v /sys:/host/sys:ro and pass --path.sysfs=/host/sys.
- Verify /sys/class/net/<device> files exist and are readable by the exporter's user.
- Look at the wrapped inner error for the exact sysfs path that failed.
- Update node_exporter: label-collection failures may be downgraded to per-device skips in newer releases.
- If labels are not needed, confirm whether your version supports disabling the label enrichment path via flags.
Example fix
// before: exporter inside container without sysfs // node_network_info labels unavailable, scrape fails // after: run with sysfs mounted docker run -v /proc:/host/proc:ro -v /sys:/host/sys:ro \ prom/node-exporter --path.procfs=/host/proc --path.sysfs=/host/sys
Defensive patterns
Strategy: fallback
Validate before calling
// preflight: sysfs labels source present
if _, err := os.Stat("/sys/class/net"); err != nil {
// labels unavailable; netdev will fail on getNetDevLabels
log.Printf("sysfs unavailable: %v", err)
} Try / catch
err := collector.Update(ch)
if err != nil && strings.Contains(err.Error(), "couldn't get netdev labels") {
logger.Warn("netdev labels unavailable; proceeding without info labels", "cause", err)
} Prevention
- Mount /sys:ro in containers and set --path.sysfs correctly
- Keep exporter user permissions permissive enough for sysfs reads
- Upgrade node_exporter so label failures degrade to warnings
- Track this error in logs distinct from the netstats error to isolate sysfs issues
When it happens
Trigger: getNetDevLabels() returns an error — on Linux it walks /sys/class/net/<dev> to read label attributes; it fails when /sys is missing/unmounted, unreadable due to permissions, or a sysfs read returns an I/O error mid-walk.
Common situations: Containers without /sys bind-mounted (very common misconfiguration); sysfs read race when an interface is hot-removed between stats and label collection; running node_exporter as a non-root user with restrictive LSM rules.
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 get sysfs device info
- couldn't get netstats
- Could not derive a human-readable chip type for
- getifaddrs() failed
- getifaddrs() failed
AI-assisted analysis of prometheus/node_exporter@17ddd77c59 (2026-09-07).
Data as JSON: /api/errors/4d6db2a1c2ae46dd.
Report an issue: GitHub.
Appendix: source
Thrown at collector/netdev_common.go:117
prometheus.BuildFQName(namespace, c.subsystem, key+"_total"),
fmt.Sprintf("Network device statistic %s.", key),
labels,
nil,
)
}
return c.metricDescs[key]
}
func (c *netDevCollector) Update(ch chan<- prometheus.Metric) error {
netDev, err := getNetDevStats(&c.deviceFilter, c.logger)
if err != nil {
return fmt.Errorf("couldn't get netstats: %w", err)
}
netDevLabels, err := getNetDevLabels()
if err != nil {
return fmt.Errorf("couldn't get netdev labels: %w", err)
}
for dev, devStats := range netDev {
if !*netdevDetailedMetrics {
legacy(devStats)
}
labels := []string{"device"}
labelValues := []string{dev}
if devLabels, exists := netDevLabels[dev]; exists {
for labelName, labelValue := range devLabels {
labels = append(labels, labelName)
labelValues = append(labelValues, labelValue)
}
}
for key, value := range devStats {
desc := c.metricDesc(key, labels)View on GitHub (pinned to 17ddd77c59)