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
- Verify the file is readable: cat /proc/sys/kernel/threads-max as the user running node_exporter.
- If a container runtime masks /proc/sys, unmask /proc/sys/kernel/threads-max in the container spec.
- Run the exporter with sufficient privileges (root or a capability/appropriate group) to read proc sysctls.
- 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
- Ensure the exporter user can read /proc/sys/kernel/threads-max.
- Unmask /proc/sys/kernel in container specs that mask proc sysctls.
- Test the exporter's scrape under the exact production user, not just root.
- Watch for hardened images (LSMs, read-only proc) that hide sysctls.
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
- unable to retrieve limit number of maximum pids allowed
- error reading task for pid
- unable to list all threads for pid
- error reading stat for pid
- failed to open procfs
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)