prometheus/node_exporter · error

unable to retrieve limit number of maximum pids allowed

Error message

unable to retrieve limit number of maximum pids allowed: %w

What it means

Update reads /proc/sys/kernel/pid_max via readUintFromFile to expose node_processes_pids and node_processes_max_pids. This error means /proc/sys/kernel/pid_max could not be read or parsed as an unsigned integer during a scrape.

Solutions

  1. Check readability: cat /proc/sys/kernel/pid_max as the exporter's user.
  2. Unmask /proc/sys/kernel/pid_max in your container spec if a runtime is masking it.
  3. Grant the exporter user read access to proc sysctls (or run as root).
  4. Confirm the exporter is actually running on Linux against a real procfs (not a truncated fixture mount).
Defensive patterns

Strategy: validation

Validate before calling

// before scraping, as the exporter user
if _, err := os.ReadFile("/proc/sys/kernel/pid_max"); err != nil {
    log.Printf("pid_max sysctl unreadable: %v", err)
}

Try / catch

if err := c.Update(ch); err != nil {
    if strings.Contains(err.Error(), "maximum pids allowed") {
        log.Printf("pid_max unavailable in this environment: %v", err)
    }
}

Prevention

When it happens

Trigger: readUintFromFile(procFilePath("sys/kernel/pid_max")) fails because the file is absent, permission-denied, or contains non-numeric content.

Common situations: Container runtimes that mask /proc/sys/kernel/pid_max; hardened images where proc sysctls are not world-readable; running node_exporter inside a user namespace with restricted procfs visibility.

Understand the failure class

Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.

Related errors


AI-assisted analysis of prometheus/node_exporter@17ddd77c59 (2026-09-07). Data as JSON: /api/errors/c3e4a8cd85cd2910. Report an issue: GitHub.

Appendix: source

Thrown at collector/processes_linux.go:108

	ch <- prometheus.MustNewConstMetric(c.threadAlloc, prometheus.GaugeValue, float64(threads))
	maxThreads, err := readUintFromFile(procFilePath("sys/kernel/threads-max"))
	if err != nil {
		return fmt.Errorf("unable to retrieve limit number of threads: %w", err)
	}
	ch <- prometheus.MustNewConstMetric(c.threadLimit, prometheus.GaugeValue, float64(maxThreads))

	for state := range states {
		ch <- prometheus.MustNewConstMetric(c.procsState, prometheus.GaugeValue, float64(states[state]), state)
	}

	for state := range threadStates {
		ch <- prometheus.MustNewConstMetric(c.threadsState, prometheus.GaugeValue, float64(threadStates[state]), state)
	}

	pidM, err := readUintFromFile(procFilePath("sys/kernel/pid_max"))
	if err != nil {
		return fmt.Errorf("unable to retrieve limit number of maximum pids allowed: %w", err)
	}
	ch <- prometheus.MustNewConstMetric(c.pidUsed, prometheus.GaugeValue, float64(pids))
	ch <- prometheus.MustNewConstMetric(c.pidMax, prometheus.GaugeValue, float64(pidM))

	return nil
}

func (c *processCollector) getAllocatedThreads() (int, map[string]int32, int, map[string]int32, error) {
	p, err := c.fs.AllProcs()
	if err != nil {
		return 0, nil, 0, nil, fmt.Errorf("unable to list all processes: %w", err)
	}
	pids := 0
	thread := 0
	procStates := make(map[string]int32)
	threadStates := make(map[string]int32)

	for _, pid := range p {

View on GitHub (pinned to 17ddd77c59)