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
- 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
- Check that the host port is obtained via mach_host_self() and passed correctly to C.host_t(host)
- 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
- 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
- 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
- Run the exporter without a restrictive macOS sandbox/entitlement profile
- Test the collector after each macOS major upgrade
- Check kern_return_t codes in logs to catch kernel-level failures early
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
- sysctl CTL_VFS VFS_GENERIC VFS_BCACHESTAT failed
- could not retrieve CPU times
- getdevs() failed
- calloc() failed
- devstat_getdevs failed
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)