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

  1. Mount sysfs read-only into the container: -v /sys:/host/sys:ro and pass --path.sysfs=/host/sys.
  2. Verify /sys/class/net/<device> files exist and are readable by the exporter's user.
  3. Look at the wrapped inner error for the exact sysfs path that failed.
  4. Update node_exporter: label-collection failures may be downgraded to per-device skips in newer releases.
  5. 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

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


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)