prometheus/node_exporter · error

unable to retrieve limit number of threads

Error message

unable to retrieve limit number of threads: %w

What it means

After emitting the threads gauge, Update reads /proc/sys/kernel/threads-max with readUintFromFile to expose node_processes_max_threads. This error means that file could not be read or parsed as an unsigned integer, so the threads-limit metric could not be produced.

Solutions

  1. Verify the file is readable: cat /proc/sys/kernel/threads-max as the user running node_exporter.
  2. If a container runtime masks /proc/sys, unmask /proc/sys/kernel/threads-max in the container spec.
  3. Run the exporter with sufficient privileges (root or a capability/appropriate group) to read proc sysctls.
  4. If the metric is not needed and the environment cannot be changed, upgrade node_exporter or file an issue — there is no flag to skip only this metric.

Example fix

// before
// running as unprivileged user with hidepid/masked sysctls
// after
// grant read access or run exporter as root
docker run --user root --pid=host quay.io/prometheus/node-exporter ...
Defensive patterns

Strategy: validation

Validate before calling

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

Try / catch

if err := c.Update(ch); err != nil {
    if strings.Contains(err.Error(), "limit number of threads") {
        log.Printf("threads-max unavailable in this environment: %v", err)
        // degrade: keep other process metrics, drop node_processes_max_threads
    }
}

Prevention

When it happens

Trigger: readUintFromFile(procFilePath("sys/kernel/threads-max")) returns an error during a scrape — the file is missing, unreadable, or its content is not a plain integer.

Common situations: Hardened/container environments where /proc/sys/kernel is masked or read-restricted; unusual kernels or security frameworks (e.g. some LSMs) that restrict access to proc sysctls for non-root users.

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

Appendix: source

Thrown at collector/processes_linux.go:94

		pidUsed: prometheus.NewDesc(prometheus.BuildFQName(namespace, subsystem, "pids"),
			"Number of PIDs", nil, nil,
		),
		pidMax: prometheus.NewDesc(prometheus.BuildFQName(namespace, subsystem, "max_processes"),
			"Number of max PIDs limit", nil, nil,
		),
		logger: logger,
	}, nil
}
func (c *processCollector) Update(ch chan<- prometheus.Metric) error {
	pids, states, threads, threadStates, err := c.getAllocatedThreads()
	if err != nil {
		return fmt.Errorf("unable to retrieve number of allocated threads: %w", err)
	}

	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))

View on GitHub (pinned to 17ddd77c59)