prometheus/node_exporter · error

failed to open procfs

Error message

failed to open procfs: %w

What it means

getConntrackStatistics cannot initialize the procfs filesystem handle at --path.procfs and returns this wrapped error before attempting any reads. procfs.NewFS validates that the given path is a usable proc filesystem, so this indicates the configured proc path itself is wrong or inaccessible.

Solutions

  1. Pass the correct --path.procfs (e.g. /host/proc when host proc is bind-mounted there)
  2. Verify the directory exists and is a procfs mount (mount | grep proc)
  3. On non-Linux hosts, disable the conntrack collector instead

Example fix

// before
node_exporter --path.procfs=/wrong/proc
// after
node_exporter --path.procfs=/host/proc
Defensive patterns

Strategy: validation

Validate before calling

// Go: verify the proc path is usable before constructing the collector
if fi, err := os.Stat(*procPath); err != nil || !fi.IsDir() {
    return fmt.Errorf("--path.procfs %q is not a directory", *procPath)
}

Try / catch

c, err := NewNodeCollector(filters...)
if err != nil {
    if strings.Contains(err.Error(), "failed to open procfs") {
        log.Error("bad --path.procfs; check mount/flag", "err", err)
    }
    return err
}

Prevention

When it happens

Trigger: procfs.NewFS(*procPath) returns an error: --path.procfs points to a nonexistent directory, a non-procfs filesystem, or an unreadable path.

Common situations: Wrong --path.procfs value on containers/chroots; testing on macOS/Windows where /proc does not exist; mount namespace differences in Kubernetes where /proc of the host is mounted at /host/proc but the flag was not updated.

Understand the failure class

Background: "open() failed", "failed to open file", "cannot create file" — what a file open error means and how to fix it — this error's family across 42 libraries.

Related errors


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

Appendix: source

Thrown at collector/conntrack_linux.go:159

	ch <- prometheus.MustNewConstMetric(
		conntrackSearchRestart, prometheus.GaugeValue, float64(conntrackStats.searchRestart))
	return nil
}

func (c *conntrackCollector) handleErr(err error) error {
	if errors.Is(err, os.ErrNotExist) {
		c.logger.Debug("conntrack probably not loaded")
		return ErrNoData
	}
	return fmt.Errorf("failed to retrieve conntrack stats: %w", err)
}

func getConntrackStatistics() (*conntrackStatistics, error) {
	s := conntrackStatistics{}

	fs, err := procfs.NewFS(*procPath)
	if err != nil {
		return nil, fmt.Errorf("failed to open procfs: %w", err)
	}

	connStats, err := fs.ConntrackStat()
	if err != nil {
		return nil, err
	}

	for _, connStat := range connStats {
		s.found += connStat.Found
		s.invalid += connStat.Invalid
		s.ignore += connStat.Ignore
		s.insert += connStat.Insert
		s.insertFailed += connStat.InsertFailed
		s.drop += connStat.Drop
		s.earlyDrop += connStat.EarlyDrop
		s.searchRestart += connStat.SearchRestart
	}

View on GitHub (pinned to 17ddd77c59)