prometheus/node_exporter · error

failed to open procfs

Error message

failed to open procfs: %w

What it means

NewPressureStatsCollector opens the procfs filesystem at the --path.procfs location before creating PSI (pressure stall information) collectors. If procfs.NewFS fails, the collector cannot be constructed and the error is wrapped as "failed to open procfs". NewFS validates that the given path looks like a proc filesystem, so this almost always means the path is wrong or not a real procfs mount.

Solutions

  1. Verify --path.procfs points to a mounted proc filesystem (default /proc): check that $PROC/pressure exists and /proc/stat is readable.
  2. In containers, mount host procfs read-only (-v /proc:/host/proc:ro) and pass --path.procfs=/host/proc.
  3. If PSI is not needed, disable the pressure collector (--collector.pressure=false) so construction is skipped.

Example fix

// before
node_exporter --path.procfs=/host/proc  # empty mount
// after
docker run -v /proc:/host/proc:ro node-exporter --path.procfs=/host/proc
Defensive patterns

Strategy: validation

Validate before calling

func procfsReady(path string) error {
	info, err := os.Stat(filepath.Join(path, "stat"))
	if err != nil {
		return fmt.Errorf("%s is not a procfs mount: %w", path, err)
	}
	if info.IsDir() {
		return fmt.Errorf("%s/stat is not a file", path)
	}
	return nil
}

Try / catch

coll, err := NewPressureStatsCollector(logger)
if err != nil {
	logger.Warn("pressure collector unavailable", "err", err)
	coll = nil // continue without PSI metrics
}

Prevention

When it happens

Trigger: NewPressureStatsCollector -> procfs.NewFS(*procPath) returning an error because --path.procfs does not exist, is not a directory, or does not resemble a procfs mount (e.g. missing/invalid /proc/stat or /proc/meminfo sanity files).

Common situations: Containers where /proc is not mounted or is masked; a mistyped --path.procfs; running on systems where PSI is unavailable but /proc is also atypical; pointing --path.procfs at a host-mounted path lacking procfs structure.

Understand the failure class

Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.

Related errors


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

Appendix: source

Thrown at collector/pressure_linux.go:61

	ioFull  *prometheus.Desc
	mem     *prometheus.Desc
	memFull *prometheus.Desc
	irqFull *prometheus.Desc

	fs procfs.FS

	logger *slog.Logger
}

func init() {
	registerCollector("pressure", defaultEnabled, NewPressureStatsCollector)
}

// NewPressureStatsCollector returns a Collector exposing pressure stall information
func NewPressureStatsCollector(logger *slog.Logger) (Collector, error) {
	fs, err := procfs.NewFS(*procPath)
	if err != nil {
		return nil, fmt.Errorf("failed to open procfs: %w", err)
	}

	return &pressureStatsCollector{
		cpu: prometheus.NewDesc(
			prometheus.BuildFQName(namespace, "pressure", "cpu_waiting_seconds_total"),
			"Total time in seconds that processes have waited for CPU time",
			nil, nil,
		),
		io: prometheus.NewDesc(
			prometheus.BuildFQName(namespace, "pressure", "io_waiting_seconds_total"),
			"Total time in seconds that processes have waited due to IO congestion",
			nil, nil,
		),
		ioFull: prometheus.NewDesc(
			prometheus.BuildFQName(namespace, "pressure", "io_stalled_seconds_total"),
			"Total time in seconds no process could make progress due to IO congestion",
			nil, nil,
		),

View on GitHub (pinned to 17ddd77c59)