prometheus/node_exporter · error

failed to open /proc/self

Error message

failed to open /proc/self: %w

What it means

After opening procfs, NewNetStatCollector calls fs.Self() to obtain a handle on /proc/self so netstat data is read from the current process's network namespace. If procfs cannot resolve /proc/self, the constructor returns this wrapped error and the collector fails to initialize.

Solutions

  1. Ensure /proc/self exists and is readable by the exporter process (ls -l /proc/self).
  2. Check proc mount options; relax hidepid or run the exporter with sufficient privileges.
  3. In containers, mount a full /proc rather than a partial subset.
  4. Verify with --path.procfs that the configured procfs root actually contains the self entry.

Example fix

// before
proc, err := fs.Self()
if err != nil {
	return nil, fmt.Errorf("failed to open /proc/self: %w", err)
}
// after (add path context for debugging)
proc, err := fs.Self()
if err != nil {
	return nil, fmt.Errorf("failed to open /proc/self under %q (check hidepid/container proc mount): %w", *procPath, err)
}
Defensive patterns

Strategy: validation

Validate before calling

import "os"
// Ensure /proc/self is resolvable under the configured procfs root:
if _, err := os.Stat(*procPath + "/self"); err != nil {
	// /proc/self missing: check proc mount completeness/hidepid before init
}

Type guard

null

Try / catch

// Constructor-time handling: fail fast with actionable context
if _, err := NewNetStatCollector(logger); err != nil {
	if strings.Contains(err.Error(), "/proc/self") {
		logger.Error("procfs self-entry unreadable; check hidepid and container mounts", "err", err)
	}
	return err
}

Prevention

When it happens

Trigger: fs.Self() fails when /proc/self cannot be read or resolved, e.g. /proc is mounted but lacks the self symlink, or the process's procfs entries are hidden/unreadable (hidepid, restricted containers).

Common situations: Containers mounting a partial /proc; hidepid=2 proc mounts restricting access; chroot/minimal images without a fully populated procfs.

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

Appendix: source

Thrown at collector/netstat_linux.go:69

func init() {
	registerCollector("netstat", defaultEnabled, NewNetStatCollector)
}

// NewNetStatCollector takes and returns
// a new Collector exposing network stats.
func NewNetStatCollector(logger *slog.Logger) (Collector, error) {
	pattern := regexp.MustCompile(*netStatFields)
	fs, err := procfs.NewFS(*procPath)
	if err != nil {
		return nil, fmt.Errorf("failed to open procfs: %w", err)
	}

	// Network statistics in /proc/net are network namespace local. Reading
	// them via the current process' /proc/self/net keeps the same semantics
	// while allowing the use of the procfs parsers.
	proc, err := fs.Self()
	if err != nil {
		return nil, fmt.Errorf("failed to open /proc/self: %w", err)
	}

	return &netStatCollector{
		proc:         proc,
		fieldPattern: pattern,
		logger:       logger,
	}, nil
}

func (c *netStatCollector) Update(ch chan<- prometheus.Metric) error {
	netStats, err := c.proc.Netstat()
	if err != nil {
		return fmt.Errorf("couldn't get netstats: %w", err)
	}
	snmpStats, err := c.proc.Snmp()
	if err != nil {
		return fmt.Errorf("couldn't get SNMP stats: %w", err)
	}

View on GitHub (pinned to 17ddd77c59)