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

  1. Rebuild node_exporter from source on (or matching) the target OpenBSD release so the bcachestat struct layout matches the kernel
  2. Verify with `sysctl vfs.generic.bcachestat` that the MIB exists and is readable by the user running node_exporter
  3. Check pledge/unveil or jail restrictions and run the exporter with permissions allowing sysctl CTL_VFS access
  4. 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

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


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)