prometheus/node_exporter · error

couldn't get memory statistics, host_statistics returned

Error message

couldn't get memory statistics, host_statistics returned %d

What it means

This error comes from the macOS memory collector when the Mach call host_statistics64 (via cgo, host_statistics in the message) fails to fill the vm_statistics64 structure. The kernel returns a kern_return_t other than KERN_SUCCESS, and its integer value is embedded in the message. It indicates the process lacks the host privilege needed for HOST_VM_INFO64 or the Mach host port is invalid.

Solutions

  1. Verify the process can call host_statistics64 with HOST_VM_INFO64 outside the sandbox (run a minimal test binary); if sandboxed, add the entitlement or disable sandboxing
  2. Check that the host port is obtained via mach_host_self() and passed correctly to C.host_t(host)
  3. Log the numeric kern_return_t value and look it up in mach/kern_return.h (e.g. KERN_INVALID_ARGUMENT=4) to identify the precise cause
  4. Fall back to a different memory source (e.g. vm_stat CLI output parsed externally, sysctl vm.swapusage) or disable the meminfo collector on affected hosts
  5. Ensure the macOS SDK/kernel version supports HOST_VM_INFO64; on ancient versions fall back to HOST_VM_INFO

Example fix

// before
ret := C.host_statistics64(C.host_t(host), C.HOST_VM_INFO64, ...)
if ret != C.KERN_SUCCESS {
    return nil, fmt.Errorf("couldn't get memory statistics, host_statistics returned %d", ret)
}
// after
ret := C.host_statistics64(C.host_t(host), C.HOST_VM_INFO64, ...)
if ret != C.KERN_SUCCESS {
    return nil, fmt.Errorf("couldn't get memory statistics, host_statistics returned %d (kern_return_t)", ret)
}
// diagnose: if ret == KERN_INVALID_ARGUMENT, switch to C.HOST_VM_INFO on older kernels
Defensive patterns

Strategy: try-catch

Try / catch

collector, err := NewNodeCollector(...)
if err != nil {
    // NewMeminfoCollector is invoked during registry setup; log and continue
    // without the memory collector rather than aborting the exporter
    log.Printf("meminfo collector unavailable: %v", err)
}

Prevention

When it happens

Trigger: getMemInfo calls C.host_statistics64(C.host_t(host), C.HOST_VM_INFO64, ...) and the returned kern_return_t != KERN_SUCCESS — e.g. the host port was obtained incorrectly, the requested flavor is not accepted by the kernel, or a sandbox/severely restricted environment blocks the host_info call.

Common situations: Running node_exporter under a macOS sandbox or hardened runtime without the required host info entitlement; running on very old macOS kernels where HOST_VM_INFO64 is unavailable; embedding the collector in a process whose task self/host ports were manipulated; failure after macOS version upgrades that changed mach port behaviors.

Understand the failure class

Background: "API request failed": what wrapped HTTP errors from external APIs mean and how to find the real cause — this error's family across 29 libraries.

Related errors


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

Appendix: source

Thrown at collector/meminfo_darwin.go:54

// NewMeminfoCollector returns a new Collector exposing memory stats.
func NewMeminfoCollector(logger *slog.Logger) (Collector, error) {
	return &meminfoCollector{
		logger: logger,
	}, nil
}

func (c *meminfoCollector) getMemInfo() (map[string]float64, error) {
	host := C.mach_host_self()
	infoCount := C.mach_msg_type_number_t(C.HOST_VM_INFO64_COUNT)
	vmstat := C.vm_statistics64_data_t{}
	ret := C.host_statistics64(
		C.host_t(host),
		C.HOST_VM_INFO64,
		C.host_info_t(unsafe.Pointer(&vmstat)),
		&infoCount,
	)
	if ret != C.KERN_SUCCESS {
		return nil, fmt.Errorf("couldn't get memory statistics, host_statistics returned %d", ret)
	}
	totalb, err := unix.Sysctl("hw.memsize")
	if err != nil {
		return nil, err
	}

	swapraw, err := unix.SysctlRaw("vm.swapusage")
	if err != nil {
		return nil, err
	}
	swap := (*C.xsw_usage_t)(unsafe.Pointer(&swapraw[0]))

	// Syscall removes terminating NUL which we need to cast to uint64
	total := binary.LittleEndian.Uint64([]byte(totalb + "\x00"))

	var pageSize C.vm_size_t
	C.host_page_size(C.host_t(host), &pageSize)

View on GitHub (pinned to 17ddd77c59)