prometheus/node_exporter · error

couldn't get netstats

Error message

couldn't get netstats: %w

What it means

The netdev collector wraps any error from getNetDevStats() — the platform-specific function that gathers per-interface RX/TX counters (from /proc/net/dev on Linux, net.Interfaces + IOKit/sysctl on darwin, etc.) — as 'couldn't get netstats'. Because this is the first step of netDevCollector.Update, the whole node_network_* metric set is dropped for that scrape when it fails.

Solutions

  1. Read the wrapped inner error in the log line to identify the platform-level cause.
  2. Verify the procfs mount path matches the --path.procfs flag (default /proc) and that /proc/net/dev is readable: cat /proc/net/dev.
  3. In containers, mount /proc (or use the host PID namespace pattern used by the official node-exporter manifests).
  4. Check hidepid mount options on /proc; node_exporter needs read access to netdev entries.
  5. Run the collector alone (node_exporter --collector.disable-defaults --collector.netdev) to isolate the failure.
Defensive patterns

Strategy: try-catch

Validate before calling

// preflight: netdev source must be readable
f, err := os.Open(filepath.Join(*procPath, "net", "dev"))
if err != nil {
	return fmt.Errorf("netdev stats source unreadable: %w", err)
}
f.Close()

Try / catch

err := collector.Update(ch)
if err != nil {
	if strings.Contains(err.Error(), "couldn't get netstats") {
		logger.Error("netdev scrape failed; inspect wrapped cause", "err", err)
		return nil // skip scrape instead of crashing exporter
	}
	return err
}

Prevention

When it happens

Trigger: getNetDevStats(&c.deviceFilter, c.logger) returns error — on Linux this means procfs open or /proc/net/dev parse failure (see procNetDevStats); on darwin a net.Interfaces() failure; the error text is always this wrapper, so look at %w for the cause.

Common situations: --path.procfs pointing at a wrong or unmounted path; container missing /proc/net/dev; /proc mounted with hidepid restrictions; on darwin, network stack initialization failures in sandboxed/test 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


AI-assisted analysis of prometheus/node_exporter@17ddd77c59 (2026-09-07). Data as JSON: /api/errors/f494e316105070ce. Report an issue: GitHub.

Appendix: source

Thrown at collector/netdev_common.go:112

	c.metricDescsMutex.Lock()
	defer c.metricDescsMutex.Unlock()

	if _, ok := c.metricDescs[key]; !ok {
		c.metricDescs[key] = prometheus.NewDesc(
			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)

View on GitHub (pinned to 17ddd77c59)