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:
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) → correct uint64 ✓
References
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 |
Bug Report:
/proc/statprocesses field overflow causes entireStat()parsing to failAffected Code
stat.go—parseStat()function,processescase (lines ~177-180):Root Cause
The
processesfield in/proc/statrepresents "number of forks since boot" and is stored as anunsigned intin the Linux kernel. On long-running systems (300+ days) with high process churn, this counter wraps around and/proc/statreports a negative integer string:strconv.ParseUintcannot parse negative values, causing the entireparseStat()function to return an error. This breaks ALL consumers that depend onStat(), including: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
Tested and confirmed failing on:
Proposed Fix
Use
strconv.ParseIntinstead ofstrconv.ParseUintfor theprocessesfield. In Go, converting a negativeint64touint64produces the correct unsigned representation via two's complement:This handles both cases:
ParseInt("12345")→int64(12345)→uint64(12345)✓ParseInt("-1948031333")→int64(-1948031333)→ correctuint64✓References
/proc/statimplementation: https://gitlab.com/linux-kernel/stable/-/blob/master/fs/proc/stat.cEnvironment
/proc/statprocesses