prometheus/node_exporter · warning

no CPU power status has been recorded

Error message

no CPU power status has been recorded

What it means

fetchCPUPowerStatus on macOS queries IOKit for the CPU power status dictionary; when IOKit returns kIOReturnNotFound the exporter has no recorded CPU power status and returns this error. It is distinct from other IOKit error codes, which produce a hex-code error instead.

Solutions

  1. Accept the absence: run the thermal collector only on supported Apple hardware, or disable it via --collector.thermal.
  2. Verify SMC availability on the host (real Mac hardware required); on VMs the metric cannot exist.
  3. Check for macOS updates/SMC firmware updates that might publish the key.

Example fix

// before
status, err := fetchCPUPowerStatus(logger) // errors on VMs
// after
status, err := fetchCPUPowerStatus(logger)
if err != nil {
    logger.Debug("CPU power status unavailable", "err", err)
    return nil // skip metric instead of failing collection
}
Defensive patterns

Strategy: fallback

Try / catch

status, err := fetchCPUPowerStatus(logger)
if err != nil {
    if err.Error() == "no CPU power status has been recorded" {
        logger.Debug("CPU power status not available on this hardware")
        return nil
    }
    return err
}

Prevention

When it happens

Trigger: Update -> fetchCPUPowerStatus when the IOService (AppleSMC power-status style) dictionary lookup returns kIOReturnNotFound, i.e., the key has never been recorded by the SMC.

Common situations: Virtual machines or Hackintosh/unsupported hardware where the SMC does not publish CPU power status; macOS on platforms lacking the specific SMC key.

Understand the failure class

Background: "unsupported platform" / "not supported on this platform" errors: what they mean and how to fix them — this error's family across 47 libraries.

Related errors


AI-assisted analysis of prometheus/node_exporter@17ddd77c59 (2026-09-07). Data as JSON: /api/errors/b5419aa3a598ad33. Report an issue: GitHub.

Appendix: source

Thrown at collector/thermal_darwin.go:138

		ch <- c.cpuAvailableCPU.mustNewConstMetric(float64(value))
	}
	if value, ok := cpuPowerStatus[(string(C.kIOPMCPUPowerLimitProcessorSpeedKey))]; ok {
		ch <- c.cpuSpeedLimit.mustNewConstMetric(float64(value) / 100.0)
	}

	return c.updateTemperatures(ch)
}

func fetchCPUPowerStatus() (map[string]int, error) {
	cfDictRef, _ := C.FetchThermal()
	defer func() {
		if cfDictRef.ref != 0x0 {
			C.CFRelease(C.CFTypeRef(cfDictRef.ref))
		}
	}()

	if C.kIOReturnNotFound == cfDictRef.ret {
		return nil, errors.New("no CPU power status has been recorded")
	}

	if C.kIOReturnSuccess != cfDictRef.ret {
		return nil, fmt.Errorf("no CPU power status with error code 0x%08x", int(cfDictRef.ret))
	}

	// mapping CFDictionary to map
	cfDict := CFDict(cfDictRef.ref)
	return mappingCFDictToMap(cfDict), nil
}

type CFDict uintptr

func mappingCFDictToMap(dict CFDict) map[string]int {
	if C.CFNullRef(dict) == C.kCFNull {
		return nil
	}
	cfDict := C.CFDictionaryRef(dict)

View on GitHub (pinned to 17ddd77c59)