prometheus/node_exporter · error
unable to get isolated cpus
Error message
unable to get isolated cpus: %w
What it means
After opening sysfs, NewCPUCollector reads the isolated CPU set (sfs.IsolatedCPUs(), backed by /sys/devices/system/cpu/isolated). If reading it fails for any reason other than os.ErrNotExist, the error is fatal and wrapped with this message; a missing file is tolerated (the feature simply isn't in use) and only logged at debug level.
Solutions
- Ensure the exporter can read /sys/devices/system/cpu/isolated (check mount and file permissions)
- If isolation is not used and the file is absent, no action needed — this error means a read failed despite the file existing
- Update procfs/sysfs libraries (or the exporter) if the CPU-list format cannot be parsed
Example fix
// before isolcpus, err := sfs.IsolatedCPUs() // permission denied, fatal // after chmod / adjust container mounts: -v /sys:/host/sys:ro and --path.sysfs=/host/sys
Defensive patterns
Strategy: try-catch
Validate before calling
// Go: probe the isolated file before relying on the feature
if b, err := os.ReadFile(filepath.Join(*sysPath, "devices/system/cpu/isolated")); err != nil && !os.IsNotExist(err) {
log.Warn("cannot read isolated CPUs", "err", err)
} else {
_ = b
} Type guard
func isolatedReadable(sysPath string) bool {
_, err := os.ReadFile(filepath.Join(sysPath, "devices/system/cpu/isolated"))
return err == nil || os.IsNotExist(err)
} Try / catch
if err := run(); err != nil {
if strings.Contains(err.Error(), "unable to get isolated cpus") {
log.Warn("isolated CPU info unavailable; continuing without it", "err", err)
} else {
return err
}
} Prevention
- Keep /sys/devices/system/cpu world-readable in deployment images
- Avoid partial bind-mounts that shadow the isolated file
- Upgrade exporter/procfs if CPU-list parsing fails on your kernel
When it happens
Trigger: sfs.IsolatedCPUs() returns a non-ENOENT error, e.g. permission denied on /sys/devices/system/cpu/isolated or a malformed/unparseable CPU list.
Common situations: Hardened containers restricting /sys read access; sysfs mounted with unusual permissions; kernel/sysfs variants exposing the file in an unexpected format; bind-mounting a file (not the dir) over isolated.
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
- failed to open sysfs
- failed to open sysfs
- could not retrieve CPU times
- Invalid cpu number
- Could not derive a human-readable chip type for
AI-assisted analysis of prometheus/node_exporter@17ddd77c59 (2026-09-07).
Data as JSON: /api/errors/6953b21f5b809392.
Report an issue: GitHub.
Appendix: source
Thrown at collector/cpu_linux.go:88
registerCollector("cpu", defaultEnabled, NewCPUCollector)
}
// NewCPUCollector returns a new Collector exposing kernel/system statistics.
func NewCPUCollector(logger *slog.Logger) (Collector, error) {
pfs, err := procfs.NewFS(*procPath)
if err != nil {
return nil, fmt.Errorf("failed to open procfs: %w", err)
}
sfs, err := sysfs.NewFS(*sysPath)
if err != nil {
return nil, fmt.Errorf("failed to open sysfs: %w", err)
}
isolcpus, err := sfs.IsolatedCPUs()
if err != nil {
if !os.IsNotExist(err) {
return nil, fmt.Errorf("unable to get isolated cpus: %w", err)
}
logger.Debug("couldn't open isolated file", "error", err)
}
c := &cpuCollector{
procfs: pfs,
sysfs: sfs,
cpu: nodeCPUSecondsDesc,
cpuInfo: prometheus.NewDesc(
prometheus.BuildFQName(namespace, cpuCollectorSubsystem, "info"),
"CPU information from /proc/cpuinfo.",
[]string{"package", "core", "cpu", "vendor", "family", "model", "model_name", "microcode", "stepping", "cachesize"}, nil,
),
cpuFrequencyHz: prometheus.NewDesc(
prometheus.BuildFQName(namespace, cpuCollectorSubsystem, "frequency_hertz"),
"CPU frequency in hertz from /proc/cpuinfo.",
[]string{"package", "core", "cpu"}, nil,
),View on GitHub (pinned to 17ddd77c59)