prometheus/node_exporter · error

failed to open procfs

Error message

failed to open procfs: %w

What it means

NewSchedstatCollector wraps the error from procfs.NewFS(*procPath) with 'failed to open procfs'. The configured proc filesystem path (--path.procfs, default /proc) could not be opened as a valid procfs mount, so the collector cannot be constructed.

Solutions

  1. Fix --path.procfs to point at a mounted proc filesystem (usually /proc)
  2. Mount /proc into the container or bind-mount it at the configured path
  3. Verify the path contains typical proc files (stat, uptime) before starting

Example fix

// before
node_exporter --path.procfs=/host/proc-not-mounted
// after
node_exporter --path.procfs=/host/proc  # where /host/proc is a bind-mounted /proc
Defensive patterns

Strategy: validation

Validate before calling

func ensureProcfs(path string) error {
	if _, err := os.Stat(filepath.Join(path, "stat")); err != nil {
		return fmt.Errorf("%q is not a mounted procfs: %w", path, err)
	}
	return nil
}
// call before starting: ensureProcfs(*procPath)

Try / catch

c, err := NewSchedstatCollector(logger)
if err != nil {
	logger.Error("schedstat collector not registered", "err", err)
}

Prevention

When it happens

Trigger: Starting node_exporter with --path.procfs pointing to a nonexistent or non-procfs directory; NewSchedstatCollector fails at construction time and the scheduler-statistics collector never registers.

Common situations: Running in a container with /proc mounted at a different host path; typo in --path.procfs; minimal/chroot images without /proc mounted.

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/ba3a9f631040f6a1. Report an issue: GitHub.

Appendix: source

Thrown at collector/schedstat_linux.go:57

		prometheus.BuildFQName(namespace, "schedstat", "waiting_seconds_total"),
		"Number of seconds spent by processing waiting for this CPU.",
		[]string{"cpu"},
		nil,
	)

	timeslicesTotal = prometheus.NewDesc(
		prometheus.BuildFQName(namespace, "schedstat", "timeslices_total"),
		"Number of timeslices executed by CPU.",
		[]string{"cpu"},
		nil,
	)
)

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

	return &schedstatCollector{fs, logger}, nil
}

type schedstatCollector struct {
	fs     procfs.FS
	logger *slog.Logger
}

func init() {
	registerCollector("schedstat", defaultEnabled, NewSchedstatCollector)
}

func (c *schedstatCollector) Update(ch chan<- prometheus.Metric) error {
	stats, err := c.fs.Schedstat()
	if err != nil {
		if errors.Is(err, os.ErrNotExist) {

View on GitHub (pinned to 17ddd77c59)