prometheus/node_exporter · error

failed to open procfs

Error message

failed to open procfs: %w

What it means

The Linux time collector's update() opens the sysfs filesystem via sysfs.NewFS(*sysPath) on every scrape and wraps any open failure as 'failed to open procfs: %w' (the message says procfs but the code opens sysfs — a historical misnomer). Failure means the configured sys path does not exist or is unreadable, so no clocksource/clockevent metrics can be produced.

Solutions

  1. Point --path.sysfs at a valid sysfs directory (typically /sys).
  2. Mount /sys inside the container running node_exporter.
  3. Check filesystem permissions allow the exporter user to traverse the path.
  4. Ignore the misleading 'procfs' wording — the actual path to fix is the sysfs one.
Defensive patterns

Strategy: validation

Validate before calling

if fi, err := os.Stat(sysfsPath); err != nil || !fi.IsDir() {
    // skip enabling the time collector
}

Try / catch

if err := c.Update(ch); err != nil {
    if errors.Is(err, ErrNoData) { return }
    logger.Error("time scrape failed", "err", err)
}

Prevention

When it happens

Trigger: timeCollector.update (invoked from Update each scrape) when sysfs.NewFS(*sysPath) errors because --path.sysfs points to a missing path or a file rather than a directory.

Common situations: Containers without /sys mounted, wrong --path.sysfs value, or bind-mounting /sys read-only with restricted permissions that block directory traversal.

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

Appendix: source

Thrown at collector/time_linux.go:29

// See the License for the specific language governing permissions and
// limitations under the License.

//go:build !notime

package collector

import (
	"fmt"
	"strconv"

	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/procfs/sysfs"
)

func (c *timeCollector) update(ch chan<- prometheus.Metric) error {
	fs, err := sysfs.NewFS(*sysPath)
	if err != nil {
		return fmt.Errorf("failed to open procfs: %w", err)
	}

	clocksources, err := fs.ClockSources()
	if err != nil {
		return fmt.Errorf("couldn't get clocksources: %w", err)
	}
	c.logger.Debug("in Update", "clocksources", fmt.Sprintf("%v", clocksources))

	for i, clocksource := range clocksources {
		is := strconv.Itoa(i)
		for _, cs := range clocksource.Available {
			ch <- c.clocksourcesAvailable.mustNewConstMetric(1.0, is, cs)
		}
		ch <- c.clocksourceCurrent.mustNewConstMetric(1.0, is, clocksource.Current)
	}
	return nil
}

View on GitHub (pinned to 17ddd77c59)