prometheus / prometheus/procfs
stat.go: /proc/stat processes field overflow causes parseStat() to fail entirely
Nobody has claimed this yet.
- Dominant language
- Go
- Stars
- 883
- Forks
- 388
- Avg merge
- 13h 28m
- Merged PRs (30d)
- 3
Description
Bug Report: /proc/stat processes field overflow causes entire Stat() parsing to fail
Affected Code
stat.go — parseStat() function, processes case (lines ~177-180):
case parts[0] == "processes":
if stat.ProcessCreated, err = strconv.ParseUint(parts[1], 10, 64); err != nil {
return Stat{}, fmt.Errorf("%w: couldn't parse %q (processes): %w", ErrFileParse, parts[1], err)
}
Root Cause
The processes field in /proc/stat represents "number of forks since boot" and is stored as an unsigned int in the Linux kernel. On long-running systems (300+ days) with high process churn, this counter wraps around and /proc/stat reports a negative integer string:
processes -1948031333
strconv.ParseUint cannot parse negative values, causing the entire parseStat() function to return an error. This breaks ALL consumers that depend on Stat(), including:
- node_exporter CPU collector — zero CPU metrics exposed
- node_exporter stat collector — zero stat metrics exposed
Impact
This affects any system with >4 billion process forks since boot. In containerized environments (Kubernetes), containers start and stop frequently, accelerating the counter overflow.
Reproduction
# On a system with uptime >300 days:
cat /proc/stat | grep "^processes"
# processes -1948031333 ← negative!
# Any code calling fs.Stat() fails:
# "couldn't parse \"-1948031333\" (processes): strconv.ParseUint: parsing \"-1948031333\": invalid syntax"
Tested and confirmed failing on:
- node_exporter v1.3.1 through v1.8.2 (all versions)
- procfs v0.21.0 (latest as of June 2026)
- Linux kernel 5.x, system uptime 388 days
Proposed Fix
Use strconv.ParseInt instead of strconv.ParseUint for the processes field. In Go, converting a negative int64 to uint64 produces the correct unsigned representation via two's complement:
case parts[0] == "processes":
v, err := strconv.ParseInt(parts[1], 10, 64)
if err != nil {
// Don't fail the entire Stat() — skip this field gracefully
break
}
stat.ProcessCreated = uint64(v)
This handles both cases:
- Normal:
ParseInt("12345")→int64(12345)→uint64(12345)✓ - Overflowed:
ParseInt("-1948031333")→int64(-1948031333)→ correctuint64✓
References
- node_exporter issue: https://github.com/prometheus/node_exporter/issues/1882
- Linux kernel
/proc/statimplementation: https://gitlab.com/linux-kernel/stable/-/blob/master/fs/proc/stat.c
Environment
| Component | Version |
|---|---|
| procfs | master (v0.21.0) |
| node_exporter | v1.3.1 / v1.8.2 |
| Linux kernel | 5.x |
| System uptime | 388 days |
/proc/stat processes |
-1948031333 |
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in stat.go at parseStat(), specifically the processes case around lines 177-180, and reproduce the failure with a negative processes value such as -1948031333. Verify that Stat() no longer fails when /proc/stat reports this value and that consumers can still receive the remaining statistics.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- go
- Domain
- operating-systems
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 72/100