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
- Verify --path.procfs points to a mounted proc filesystem (default /proc): check that $PROC/pressure exists and /proc/stat is readable.
- In containers, mount host procfs read-only (-v /proc:/host/proc:ro) and pass --path.procfs=/host/proc.
- 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
- Verify /proc (or --path.procfs) is a genuine procfs mount before starting the exporter.
- In containers, mount host procfs read-only and pass the matching --path.procfs value.
- Disable --collector.pressure where PSI metrics are not required.
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
- failed to retrieve pressure stats
- ZFS / ZFS statistics are not available
- failed to open procfs
- could not get power_supply class info
- error obtaining power_supply class info
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)