prometheus/node_exporter · error

failed to open procfs

Error message

failed to open procfs: %w

What it means

NewXfrmCollector constructs a procfs.FS rooted at the --path.procfs flag and fails immediately if the filesystem cannot be opened/validated. The xfrm collector reads /proc/net/stat/xfrm_statistics via procfs; if the procfs mount point is inaccessible the collector constructor returns this wrapped error and the collector is never registered.

Solutions

  1. Verify the --path.procfs value points to a valid procfs mount (ls <path>/net/stat/xfrm_statistics must work).
  2. In containers, bind-mount the host's /proc (e.g. -v /proc:/host/proc:ro and --path.procfs=/host/proc).
  3. Ensure /proc is mounted before node_exporter starts (startup ordering / mount namespace setup).
  4. Since xfrm is disabled by default, simply don't enable it (--collector.xfrm) if not needed.
  5. Check permissions on the procfs path for the user running node_exporter.

Example fix

// before
node_exporter --collector.xfrm --path.procfs=/host/proc   # /host/proc not mounted
// after
docker run -v /proc:/host/proc:ro ... node_exporter --collector.xfrm --path.procfs=/host/proc
Defensive patterns

Strategy: validation

Validate before calling

// Go: validate the procfs root before constructing the collector
p := *procPath
if fi, err := os.Stat(filepath.Join(p, "net", "stat", "xfrm_statistics")); err != nil || fi.IsDir() {
    // xfrm stats unavailable at this procfs path; don't enable the xfrm collector
}
if fi, err := os.Stat(p); err != nil || !fi.IsDir() {
    log.Fatalf("procfs path %q is not a directory", p)
}

Try / catch

coll, err := collector.NewXfrmCollector(logger)
if err != nil {
    if strings.Contains(err.Error(), "failed to open procfs") {
        logger.Warn("procfs unavailable; xfrm collector disabled", "err", err)
        coll = nil
    } else {
        return err
    }
}

Prevention

When it happens

Trigger: procfs.NewFS(*procPath) fails because the path given by --path.procfs does not exist, is not a directory, or cannot be accessed — raised at collector construction time (also reproduced directly by TestXfrmStats in tests).

Common situations: Passing a wrong --path.procfs when running node_exporter in a container with a bind-mounted /proc at a different location, pointing procfs at a host mount that isn't mounted yet, running tests without a realistic /proc (the test uses a fixture path), chroot environments lacking /proc.

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

Appendix: source

Thrown at collector/xfrm.go:39

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

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

func init() {
	registerCollector("xfrm", defaultDisabled, NewXfrmCollector)
}

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

	return &xfrmCollector{
		fs:     fs,
		logger: logger,
	}, nil
}

var (
	xfrmInErrorDesc = prometheus.NewDesc(
		prometheus.BuildFQName(namespace, "xfrm", "in_error_packets_total"),
		"All errors not matched by other",
		nil, nil,
	)
	xfrmInBufferErrorDesc = prometheus.NewDesc(
		prometheus.BuildFQName(namespace, "xfrm", "in_buffer_error_packets_total"),
		"No buffer is left",
		nil, nil,

View on GitHub (pinned to 17ddd77c59)