prometheus/node_exporter · error
sysctl CTL_VFS VFS_GENERIC VFS_BCACHESTAT failed
Error message
sysctl CTL_VFS VFS_GENERIC VFS_BCACHESTAT failed: %w
What it means
This error is returned by getMemInfo in the OpenBSD meminfo collector when the cgo wrapper C.sysctl_bcstats fails to read the buffer cache statistics via the sysctl CTL_VFS/VFS_GENERIC/VFS_BCACHESTAT MIB. The kernel rejected the sysctl call (or the cgo helper failed), so buffer cache stats cannot be collected and the wrapped errno is surfaced with %w. node_exporter throws it because the meminfo metrics on OpenBSD depend on both VM_UVMEXP and VFS bcachestat data.
Solutions
- Rebuild node_exporter from source on (or matching) the target OpenBSD release so the bcachestat struct layout matches the kernel
- Verify with `sysctl vfs.generic.bcachestat` that the MIB exists and is readable by the user running node_exporter
- Check pledge/unveil or jail restrictions and run the exporter with permissions allowing sysctl CTL_VFS access
- Update to the latest node_exporter, as the cgo sysctl wrapper may have fixes for newer kernels
Example fix
// before (struct mismatch after kernel upgrade)
if _, err := C.sysctl_bcstats(&bcstats); err != nil {
return nil, fmt.Errorf("sysctl CTL_VFS VFS_GENERIC VFS_BCACHESTAT failed: %w", err)
}
// after: rebuild/redeploy a binary compiled on the matching OpenBSD release;
// no code change needed if struct layout was the cause. Alternatively, skip
// bcachestat gracefully:
if _, err := C.sysctl_bcstats(&bcstats); err != nil {
logger.Debug("bcachestat unavailable", "err", err)
bcstats = C.struct_bcachestat{}
} Defensive patterns
Strategy: fallback
Validate before calling
// shell check before deploying // sysctl vfs.generic.bcachestat && echo ok || echo 'bcachestat unavailable'
Try / catch
metrics, err := collector.getMemInfo()
if err != nil {
if strings.Contains(err.Error(), "VFS_BCACHESTAT") {
logger.Warn("bcachestat sysctl unavailable; meminfo partial/absent", "err", err)
return nil // degrade instead of failing the scrape
}
return err
} Prevention
- Pin node_exporter builds to the matching OpenBSD release
- Smoke-test `sysctl vfs.generic.bcachestat` in deployment scripts
- Review pledge/jail policies before sandboxing the exporter
When it happens
Trigger: Calling the meminfo collector on OpenBSD when sysctl vfs.generic.bcachestat is unavailable, restricted, or its struct size no longer matches what the kernel expects (kernel/userland mismatch after an OpenBSD version upgrade).
Common situations: Running a node_exporter binary built against a different OpenBSD release than the running kernel; hardened kernel restrictions on sysctl access; running inside a restricted jail/pledge(4) sandbox that blocks CTL_VFS lookups.
Related errors
- sysctl CTL_VM VM_UVMEXP failed
- could not retrieve CPU times
- getifaddrs() failed
- couldn't get memory statistics, host_statistics returned
- sysctl(vm.stats.vm.v_page_size) failed
AI-assisted analysis of prometheus/node_exporter@17ddd77c59 (2026-09-07).
Data as JSON: /api/errors/ba54ffa5249269bb.
Report an issue: GitHub.
Appendix: source
Thrown at collector/meminfo_openbsd.go:76
}
// 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) {
var uvmexp C.struct_uvmexp
var bcstats C.struct_bcachestats
if _, err := C.sysctl_uvmexp(&uvmexp); err != nil {
return nil, fmt.Errorf("sysctl CTL_VM VM_UVMEXP failed: %w", err)
}
if _, err := C.sysctl_bcstats(&bcstats); err != nil {
return nil, fmt.Errorf("sysctl CTL_VFS VFS_GENERIC VFS_BCACHESTAT failed: %w", err)
}
ps := float64(uvmexp.pagesize)
// see uvm(9)
return map[string]float64{
"active_bytes": ps * float64(uvmexp.active),
"cache_bytes": ps * float64(bcstats.numbufpages),
"free_bytes": ps * float64(uvmexp.free),
"inactive_bytes": ps * float64(uvmexp.inactive),
"size_bytes": ps * float64(uvmexp.npages),
"swap_size_bytes": ps * float64(uvmexp.swpages),
"swap_used_bytes": ps * float64(uvmexp.swpginuse),
"swapped_in_pages_bytes_total": ps * float64(uvmexp.pgswapin),
"swapped_out_pages_bytes_total": ps * float64(uvmexp.pgswapout),
"wired_bytes": ps * float64(uvmexp.wired),
}, nil
}View on GitHub (pinned to 17ddd77c59)