prometheus/node_exporter · error

failed to open procfs

Error message

failed to open procfs: %w

What it means

NewUDPqueuesCollector wraps procfs.NewFS(*procPath) failures as 'failed to open procfs: %w'. procfs.NewFS validates that the path (from --path.procfs, default /proc) exists and is a directory, so a constructor failure means no UDP queue metrics can ever be collected from this instance.

Solutions

  1. Ensure /proc exists and is a mounted procfs directory.
  2. Fix the --path.procfs flag to the correct path.
  3. In containers, mount /proc from the host (or run with the proper volume mounts).
  4. Verify the exporter user can stat/traverse the procfs directory.

Example fix

// before
node_exporter --path.procfs=/nonexistent/proc
// after
node_exporter --path.procfs=/proc
Defensive patterns

Strategy: validation

Validate before calling

if fi, err := os.Stat(procfsPath); err != nil || !fi.IsDir() {
    // procfs unavailable: don't enable udp_queues collector
}

Try / catch

c, err := collector.NewUDPqueuesCollector(logger)
if err != nil {
    logger.Warn("udp_queues collector disabled", "err", err)
} else {
    registry.MustRegister(c)
}

Prevention

When it happens

Trigger: Calling NewUDPqueuesCollector when --path.procfs points to a nonexistent path or a regular file instead of a mounted procfs directory.

Common situations: Containers without /proc mounted or with an altered --path.procfs, typo'd systemd flag values, and host-path remounts in Kubernetes that hide /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/b5e425a3fbf69202. Report an issue: GitHub.

Appendix: source

Thrown at collector/udp_queues_linux.go:44

)

type (
	udpQueuesCollector struct {
		fs     procfs.FS
		desc   *prometheus.Desc
		logger *slog.Logger
	}
)

func init() {
	registerCollector("udp_queues", defaultEnabled, NewUDPqueuesCollector)
}

// NewUDPqueuesCollector returns a new Collector exposing network udp queued bytes.
func NewUDPqueuesCollector(logger *slog.Logger) (Collector, error) {
	fs, err := procfs.NewFS(*procPath)
	if err != nil {
		return nil, fmt.Errorf("failed to open procfs: %w", err)
	}
	return &udpQueuesCollector{
		fs: fs,
		desc: prometheus.NewDesc(
			prometheus.BuildFQName(namespace, "udp", "queues"),
			"Number of allocated memory in the kernel for UDP datagrams in bytes.",
			[]string{"queue", "ip"}, nil,
		),
		logger: logger,
	}, nil
}

func (c *udpQueuesCollector) Update(ch chan<- prometheus.Metric) error {

	s4, errIPv4 := c.fs.NetUDPSummary()
	if errIPv4 == nil {
		ch <- prometheus.MustNewConstMetric(c.desc, prometheus.GaugeValue, float64(s4.TxQueueLength), "tx", "v4")
		ch <- prometheus.MustNewConstMetric(c.desc, prometheus.GaugeValue, float64(s4.RxQueueLength), "rx", "v4")

View on GitHub (pinned to 17ddd77c59)