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

  1. Ensure the exporter can read /sys/devices/system/cpu/isolated (check mount and file permissions)
  2. If isolation is not used and the file is absent, no action needed — this error means a read failed despite the file existing
  3. 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

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


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)